Status: AUTHORISED 2026-09-27, BUILT AND VERIFIED LIVE 2026-09-27. Built by OpenCode; verified by me on
the app host and on the client surfaces — verifier 26/26, all 4,439 figures recomputed independently,
suites 209 / 35 / 178, client surfaces 22/22 (§9). One bounded gap is measured and recorded there:
Part II's group rules are stored but not applied to the arithmetic, which touches 112 packs of 4,439
(2.5%) and waits on Matthew's call.Status (as written): SPEC WRITTEN 2026-09-27. Matthew's steer (2026-09-27) is what makes
this the destination rather than a later possibility: the concession figures must work with the TRUD data and the
reimbursement data, and the combined pricing is what a client compares against their own supplier pricing. So this
phase turns the store into one defensible figure per pack, and every rule behind it is either already ingested or
measured before it is specified (§4).The one finding that changes v1's shape, measured here: the deduction does not apply to a pack that is on
concession that month, because the Drug Tariff's own Part II lists "Concessionary Price products (applicable only
for the dispensing month(s) for which the product is on concession)" among the drugs for which discount is not
deducted. On the live month that is not a corner case — Aciclovir 400mg tablets 56 is on concession at £3.61,
where the panel's current arithmetic shows a deduction-adjusted £2.08 (§5.7).
Parents: Central Reference Data (phase 7),
The Drug Tariff — Phase 4 (the rates and the fees),
Data Feeds — the Pack Link (what makes
a pack reachable), NHS Pricing View
(the surface this is computed for).
Today the pricing panel shows three things side by side and does its own small piece of arithmetic: the pack's dm+d
tariff price, the category's deduction rate, and the net that rate produces. Phase 7 replaces that with the
reimbursement position: the figure that follows from the published rules, reproducible from the store, with the rule
that produced it named on the screen.
Four rules make it, and all four are published data rather than app opinion:
And the guardrail becomes real. The comparison stage 4 of the pricing plan postponed — a contractor's purchase
price against what the NHS reimburses — needs exactly this figure. Its first visible form is a reimbursement figure
shown beside a supplier price where one exists, advisory only, never blocking an order (§5.6). The full client-facing
side-by-side is phase 8; the figure is this phase.
| Input | Where it is | State |
|---|---|---|
| dm+d release 3170926 | reference_data store |
live: 24,662 VMPs, 37,397 VMPPs, 8,686 DmdDrugTariff rows keyed to the VMPP with the payment category and the price |
| Payment category words | DmdLookup, table DT_PAYMENT_CATEGORY |
loaded with the release (Part VIIIA categories A/C/H/M, Part VIIIB/C/D seen) |
Drug Tariff release 2026-09 |
reference_data store |
live: deduction_rate_generics 20%, deduction_rate_brands 5%, deduction_rate_appliances 9.85%, single_activity_fee 152p — each with its source page and table |
Concessions 2026-09 (NHSBSA notices) |
reference_data store |
live: 216 effective lines across 7 notices, each with its dated notice |
| The pack link | ConcessionPackLink |
live: 216/216 matched, empty queue (§9 of its spec) |
| The client's own supplier prices | pricing stages 1–4 | live: imported price files, best price and spread per line |
Nothing external is needed. This phase adds no feed; it adds the calculation over feeds that are already live.
(a) The deduction scale is three flat rates (20% generics / 5% brands / 9.85% appliances) — already ingested, with
the graduated table surviving only as history.
(b) Part II is a standing document, and it is the rule this phase is currently missing. Published monthly as its
own download — "Drug Tariff Part II September 2026.pdf" on the NHSBSA Drug Tariff page, 154,503 bytes, 27 pages,
extracted to text with no OCR. Its heading is "Drugs for which discount is not deducted" and its operative sentence:
"Contractors who have not received discount in respect of the following products need not endorse the prescription.
The prescription price reimbursement will have no discount deduction applied."
It carries 8 GROUP rules and 1,463 individual items:
| Group rule | What it means for the arithmetic |
|---|---|
| Concessionary Price products (applicable only for the dispensing month(s) for which the product is on concession) | A pack on concession that month takes no deduction — the concession price is the reimbursement |
| Cold Chain Storage (ALL) | no deduction |
| Controlled Drugs, schedules 1–3 of the Misuse of Drugs Regulations 2001 | no deduction |
| Cytotoxic or Cytostatic items (ALL) | no deduction |
| Immunoglobulins (ALL) | no deduction |
| Insulins for Injection (ALL) | no deduction |
| Vaccines and Antisera (ALL) | no deduction |
| Unlicensed medicines not listed in Part VIIIB, sourced from an MHRA specials or importers licence | no deduction and endorsed with the invoice price less discount/rebate |
(c) The SAF is per item. Already the panel's rule, and the reason the net is asserted not to be
basis + 152 (the tautology that was once in a checker and is now a real check).
Run on 2026-09-27 against the live release (3170926) and the live September 2026 Part II document, using the
same deterministic normalisation as the pack link (case, whitespace, the space between a number and its unit, the
spacing around /, trailing punctuation) and no similarity score:
| Method | Result |
|---|---|
| Rule 1 — normalised name equals a live dm+d VMP or AMP name | 1,274 / 1,463 (87.1%) |
| Rule 2 — a name that states no strength means every strength of that product ("Adempas tablets" → the Adempas tablets; "Alitretinoin capsules" → both strengths) — matched on the leading product name plus the same form word | +166 |
| Total by the two rules | 1,440 / 1,463 (98.4%) |
| Residue | 23 (1.6%), in named kinds |
151 of the 1,463 entries carry the document's own (ALL) marker ("Alitretinoin capsules (ALL)") and 166 more state
no strength at all — both mean every strength of that product, which is why the rule resolves at product level.
The residue, named — these are the queue's first entries, not mysteries: bulk chemicals and reagents (Acetic acid
glacial, Chloroform liquid, Phenol liquefied, Isopropyl alcohol, Magenta powder, Benzoic acid powder);
herbal and traditional preparations (Arnica tincture, Mastic compound paste, Lorenzo's oil); nutrition and food
products (Aymes Actagain Protein Shot, KetoClassic 3:1 Meal); devices and kits (D-mine Infset … device, Passio
disposable collection kit); one reversed-order combination (Sacubitril/Valsartan tablets); and one typo in the
published document itself (Prednsiolone sodium phosphate 5mg suppositories).
Two consequences for the build. Matching is at product level, not pack level — a Part II entry names a product, and
the rule then applies to every pack beneath it, which is the opposite direction to the pack link and must be stored
that way. And the list is data, not code: it is ingested from the month's own document, matched deterministically,
queued where it cannot settle, and overridable by a human decision that holds for future months — the pack link's
discipline, applied to a second list.
The month's effective concession price for the pack where the pack link resolves one (the price the contractor is
reimbursed at); otherwise the pack's dm+d tariff price for its category; otherwise no figure at all — an
absence, never £0.00.
No deduction where either applies:
Otherwise the category rate from the live tariff release (generics 20 / brands 5 / appliances 9.85).
152p per item, carried separately and never folded into a per-pack figure.
The panel states the rule that produced the figure — "on concession this month, so no discount is deducted", or the
category rate with its release. A figure whose rule cannot be named is not defensible, and a contractor comparing it
with their own invoice will ask exactly that.
The same stored inputs always produce the same figure: an arithmetic layer over the store, with no live lookup at
render time, no scoring, and no hidden default. Where a figure cannot be derived, the screen says which input is
missing rather than showing a number.
Where the client has an imported supplier price for a pack, the derived reimbursement is shown beside it — a
figure and its basis, advisory only and never blocking an order (the rule stage 4 set for its value advisory).
This is the parking place the W4 margin question has been waiting for: the columns can now carry a real reimbursement
figure instead of a synthetic one.
Aciclovir 400mg tablets, pack 56, September 2026.
| Figure | |
|---|---|
| dm+d tariff price (the pack's category price) | £2.60 |
| Generic deduction at 20% → the panel's current net | £2.08 |
| This month's concession price (notices, via the pack link) | £3.61 |
| Deduction applied to it — none (Part II, concessionary price) | £0.00 |
| The derived reimbursement | £3.61 |
The pack is on concession, so the concession price is the reimbursement and no discount is deducted. A factor of
1.74× between the two figures on a pack a pharmacy dispenses every week — which is the whole reason this phase
exists before anything is shown to a client.
This is a calculation layer, so it is argued, not asserted:
net != basis + 152.veripath-ops/scripts/verify-<name>.py, and the client surface verified overBuilt by OpenCode — platform feature/derived-pricing @ 1c6f9a3 (off 0907677), pharmacy
feature/derived-pricing @ 78c9b2c (off e257181), deployed by revision with migrations
reference_data/0012_part_two_and_derived_pricing and pharmacy_medicines/0004 (the state-only mirror) applied; no image
build. Both trees are at the named revisions. Verified live by me, not taken on report:
veripath-ops/scripts/verify-derived-pricing.py — 26 PASS / 0 FAIL, reproduced on the app host.none_part_two row really resolves to a matched Part II item — 0 wrong on each.none_concession, 598 none_part_two; no row is without category words, so nothing falls into the(ALL) markers on both sides, no linedecided_by='rule' (no score decides anything).reference_data 209 OK (1 skipped), pharmacy_medicines 35 OK, the combinedtenancy pharmacy pharmacy_dispensing pharmacy_medicines 178 OK.concession, deductionnone_concession, the rule named on the row — the factor of 1.74 over the old arithmetic.tc.tech.one), new verifierveripath-ops/scripts/verify-derived-pricing-live.py — 22 PASS / 0 FAIL: the concession pack shows £3.61, theno_line state and no£0.00; W3 is unchanged (216 lines, no derived figure on it).§9.1 state split is live and ruled: linked / not_linked (queue) / no_line ("No price concession isno_source; the pack-link live verifier was extended for it and passespharmacy-price-counts.py identical either side (audit 235 / files 11 //infrastructure/reference-data/packs/, …/packs/<pk>/, …/part-two/ and both mutationPart II's group rules are stored as data but not applied to the arithmetic. The build applies two of them — the
concessionary-price group (as the none_concession rule) and the individual items — and the spec scoped the rest as
"a group rule the store can identify" (§5.2). Measured on the live release through dm+d's own substance and VTM
data (not name guessing): Insulins for Injection 38 packs, Vaccines and Antisera 26, Cytotoxic or Cytostatic
48 — 112 of 4,439 derived packs (2.5%) that currently take a category deduction where Part II says discount is not
deducted. Immunoglobulins resolve to none by that route.
CORRECTED 2026-09-27, same session, and the correction is mine to record: dm+d does carry the
controlled-drug schedules. I wrote that it carries no CD schedule; it does. The held release's VMP file
carries <CONTROL_DRUG_INFO> with a <CONTROL_INFO><VPID>…</VPID><CATCD>…</CATCD> per VMP — 24,483 entries —
and CATCD maps to the CONTROL_DRUG_CATEGORY lookup already loaded (0001 Schedule 1, 0002/0003 Schedule 2,
0004–0007 Schedule 3, 0008/0009 Schedule 4, 0010 Schedule 5). 825 VMPs of the release are in Schedules 1–3 and
186 of the VMPs behind our derived figures are among them. The store simply has no column for the field and the
loader never reads it (reference_data_dmdvmp carries vmp_id, vtm_id, name, abbreviation, basis_code,
pres_status_code, df_indicator_code, non_avail_code, invalid, release_id). So five of the eight Group rules are
closeable from the release we already hold — the CD schedules by loading that one field, insulins/vaccines/
immunoglobulins through dm+d's substance and VTM data, and cytotoxic/cytostatic through a curated set (the
document defines no membership). Only two remain unidentifiable: Cold Chain Storage (ALL) — no flag exists
anywhere in dm+d — and the unlicensed-specials route, which turns on the contractor's own endorsement and
invoice facts.
The error direction matters: for those 112 packs the figure shown is lower than the tariff's position, so it
understates the reimbursement rather than overstating it. AUTHORISED 2026-09-27, BUILT (1d36ddf) AND VERIFIED LIVE 2026-09-27 — see §9.3 below. The recommendation as briefed: apply
the three identifiable groups from a curated mapping held as data — insulin, vaccine/antiserum and cytotoxic
substance/VTM sets taken from dm+d — with the same queue-and-override discipline, and state the unidentifiable three as
a named limitation on the platform view so no figure implies a coverage it does not have.
Built by OpenCode (platform feature/part-two-group-rules @ 1d36ddf, off the deployed phase-7 revision
1c6f9a3; migration reference_data/0013; no pharmacy change needed) and deployed and verified by me:
migration applied, the held VMP file copied to the app host (there is no dm+d release there — it lives on VPS1),
reference_data_control_drugs, reference_data_part_two_groups and reference_data_derive_prices run,
containers restarted, reference_data_check all checks passed.
DmdVmp.control_drug_category_code, loaded from the held release, 24,662 entries loaded, 964 VMPsapplied=Falsecategory 3,248 · none_concession 216 · none_group 377 ·none_part_two 598 — and the 598 item-level rows are unchanged by this build, as briefed.reference_data_control_drugs run reports 0 rows changed, the group build re-runs to thereference_data 220 OK (2 skipped), pharmacy_medicines 35 OK, combined 178 OK.tc.tech.one): verify-derived-pricing-live.py now 27 PASS / 0 FAIL with<VPID><CATCD> and silently dropped the 179 entries that also carry <CATDT>/<CAT_PREVCD> (aThe list is 1,462 items, not the 1,463 written in §4. My pre-specification measurement (2026-09-27) counted one
line that was part of the document's running header; the build's parser and this session's careful extraction both give
1,462, with the same 151 (ALL) markers. The match rate is therefore 98.0% against the built rules (my
measured 98.4% used a looser second rule across the whole history), and the residue is 29 rather than 23 — same
named kinds, same conclusion: the list is a normalisation problem with a queue, not a mystery.
VeriPath internal. Dummy/synthetic data only — no patient-identifiable information appears in this work, and no
credential or internal address is recorded here.