This is the answer to “why does the chart stop?”, and it is a better story than a gap. Between 2006 and 2011 OGRA published a full fortnightly build-up for four products; it publishes one again, daily, from 21 July 2026; and in the fifteen years between the two there are pump prices and nothing else — not because the working was never done, but because it was not published.
What follows explains what data/price-buildup.json is, where it came from, why it starts and stops where it does, and what can and cannot honestly be done with it. Everything below is read from one archived document whose SHA-256 is recorded in data/source/ogra-buildup/manifest.json; nothing here is derived, estimated or interpolated.
The shape of the record, in one table
Four products, three eras, and where a full build-up exists rather than only a pump price:
| Product | 2006 → 1 May 2011 | 1 Jun 2011 → 20 Jul 2026 | From 21 Jul 2026 |
|---|---|---|---|
| Petrol (MS) | full build-up, 103 fortnightly rows | pump price only | full build-up, daily |
| High-speed diesel | nothing was ever published | pump price only | full build-up, daily |
| Kerosene | full build-up, 303 rows, to 1 Jun 2023 | pump price, and build-up to 2023 | pump price |
| Light diesel oil | full build-up, 103 rows | pump price only | pump price |
| HOBC | full build-up, 103 rows | nothing | nothing |
Two regime changes account for every boundary in it.
1 June 2011 — deregulation. OGRA stopped notifying the prices of motor spirit, HOBC and light diesel oil, and so stopped publishing a build-up for them. The document says so itself, printed at the foot of each of those three sections:
Effective June 1st, 2011, Refineries and OMCs have to notify ex-refinery and ex-depot prices of MS, HOBC, LDO, JP1, JP4 & JP8.
Kerosene stayed with OGRA, which is why its section runs on to 2023 while the other three stop.
21 July 2026 — daily pricing. OGRA began publishing a full daily build-up for petrol and high-speed diesel, which is where this project’s own record of the components starts. Everything between the two dates is pump prices, from PSO’s notification archive, and nothing else — not because the working was never done, but because it was not published.
High-speed diesel has never had a published build-up before July 2026. This is worth stating plainly, because it is easy to read the gap as a failure to look. It is not. OGRA’s build-up document has no diesel section in the live copy or in any of the six archived versions of it; the companion max-ex-depot document has columns for MS, HOBC, kerosene and LDO only; a sweep of roughly ten thousand OGRA document ids found no other build-up artefact of any kind. HSD’s ex-refinery price was historically worked out from PSO’s actual import cost rather than from a published formula, and it was deregulated in September 2012. Whatever working existed was internal.
The source, and why the capture is the record
OGRA keeps a page at max-ex-depot-sale-price-price-buildup-period-wise which nothing on its own site links to. On it is document 3041, titled “PRICE BUILDUP”: an Excel print with one section per product, each a fortnightly table of seven components and the ex-depot price they add up to.
OGRA overwrites that document in place as it extends the kerosene section. The live copy today begins in 2025. The motor spirit, HOBC and light diesel years are no longer in it and are not anywhere else on OGRA’s site.
So what this project reads is not OGRA’s document. It is the Wayback Machine’s capture of OGRA’s document, taken at 2023-06-07T04:37:57Z from https://ogra.org.pk/download/3041, and held at
data/source/ogra-buildup/price-buildup-3041.pdf
sha256 cf9b521e4bb7db7e57c0910033715923cce9268bfd19510c641b6f3c05141969The capture address, the capture instant, the original document address and the digest are all recorded in the manifest beside it and repeated in the written artefact. That is not ceremony. Citing “OGRA’s price build-up” for a figure that is no longer in OGRA’s price build-up would be uncheckable; citing this capture is checkable by anyone, forever, as long as the bytes are kept — and they are kept here.
The capture has a real text layer. No OCR is involved anywhere in this path.
What is in it
612 rows across four products, every one of them sum-validating.
| Section | Product identifier | Rows | Span |
|---|---|---|---|
| MS | petrol | 103 | 16 Apr 2006 → 1 May 2011 |
| HOBC | high_octane | 103 | 16 Apr 2006 → 1 May 2011 |
| Kerosene | kerosene | 303 | 16 Apr 2006 → 1 Jun 2023 |
| Light Diesel Oil | light_diesel | 103 | 16 Apr 2006 → 1 May 2011 |
Each row states eight figures in rupees per litre: ex-refinery / IPP, excise duty, petroleum levy, inland freight, OMC margin, dealer margin, sales tax, and the ex-depot sale price. On every one of the 612 rows the first seven add up to the eighth to within one paisa. That identity is asserted over all 612 rather than checked once, because it is the only thing standing between a correct series and a series shifted by a row.
HOBC is not petrol. It is a separate, higher-octane grade, dearer than petrol on every one of the 103 dates the two share. It is given its own product identifier and its own array in the artefact so that concatenating it with petrol has to be done on purpose.
Eight rows call the levy something else. On 1 and 8 July 2009 the third column is headed “Carbon Surcharge” rather than “Petroleum Levy” — the same column, renamed in the 2009-10 budget and renamed back within the month. The figure is untouched and the heading in force travels with every row as levy_as_published.
Mapping the two regimes onto one another
The 2006 regime publishes seven lines. The regime running today publishes twenty-odd. They are not the same build-up and are not forced into one shape.
What corresponds
| 2006–2011 line | Today’s line | Confidence |
|---|---|---|
| Ex-refinery / IPP | ex-refinery/import price | same quantity, same name, same place in the chain |
| Petroleum Levy | petroleum levy | same |
| OMC Margin | OMC margin | same |
| Dealer Margin | dealer margin | same |
| Sales Tax | sales tax | same |
| Ex-depot Sale Price | total | same — the price at the pump |
| Inland Freight | IFEM | a correspondence, not an identity |
The inland freight caveat matters. IFEM is the inland freight equalisation margin and plays the same role — levelling the price across the country — but the modern figure is a pooled margin set by notification where the 2006 one is a freight charge. Do not plot the two as one continuous series across 2011.
What has no counterpart
On this side, one line: the excise duty. It is 88 paisa a litre on petrol and HOBC on every row up to 1 June 2007, zero on every row of theirs from 10 June 2007 onward, and zero on kerosene and light diesel throughout. No line of the current build-up is it.
On today’s side, sixteen. This regime states the ex-refinery price as a given and shows nothing at all of how it was arrived at. Everything above that line in the modern build-up therefore has no historical counterpart at any price: the crude or product quotation, the premium, freight and insurance, the crack spread, cost and freight in dollars and in rupees, the exchange rate, the conversion factor, incidentals, ocean loss or gain, the cost at Karachi port, the exchange-rate adjustment and customs duty — plus the two subtotals the modern sheet prints and the climate support levy, which did not exist until 2025.
Both lists are written into data/price-buildup.json and asserted complete in both directions by the tests, so a line added to either regime cannot quietly go unmapped.
What must not be done with this
Do not reconstruct the missing ex-refinery price as a residual. It is arithmetically possible for 2015–2026 — pump price minus IFEM, margins, levy and sales tax — and it would produce a figure that looks exactly like the ones on this page. It would not be one. Here the components are published and their sum is a test; there the sum would be an assumption and the residual its output, absorbing every upstream error in the levy history and the margin history silently. Every figure this project publishes is one somebody published.
Do not join petrol’s 2011 components to its 2026 components. Fifteen years of a different pricing regime sit between them, one line does not correspond cleanly and sixteen do not exist on one side. A chart that runs straight across would be inventing continuity.
Reading the document: why coordinates and not pdftotext -layout
This is recorded here as well as in the code, because it is the kind of thing a maintainer rediscovers the hard way.
pdftotext -layout reads this document wrongly, and plausibly. Its first data rows come out as:
MS 28.50 0.88 13.86 2.30 1.59 1.82 7.34
29.89 0.88 12.72 3.18 1.63 1.87 7.53 56.29
Sunday, April 16, 2006 30.31 0.88 12.30 3.18 1.63 1.87 7.53 57.70Every date is attached to the following fortnight’s components, and every set of components to the following fortnight’s total. The result still adds up, still moves smoothly, and is wrong from end to end.
The cause is physical and small. The eight figure columns and the date are printed on one baseline; the ex-depot column is printed between 0.39 and 0.61 of a point lower. A layout algorithm that assigns text to lines by exact baseline puts that column on a line of its own, and the error cascades.
So the reader for this document walks the PDF content stream itself, takes the position of every piece of text from the text matrix, and groups pieces into printed rows by baseline with a ±3 point tolerance. Three points is chosen because the two quantities it separates are nowhere near each other: the largest spread within a printed row anywhere in the seven pages is 0.61pt, and the smallest gap between consecutive rows is 12.0pt. Anything from about 0.7 to about 11.9 behaves identically.
One more thing the document does that a simpler reader would trip on: it writes its dates four different ways, sometimes within a page of each other — Sunday, April 16, 2006, Friday, 22 May 2009, Sunday, December 16,2007, Sunday , June 22 2008 — and misspells the weekday as “Suturday” twice. The date is therefore assembled from a month name, a day and a year found anywhere in the cell, and the weekday is not relied on.
Two things noticed in passing
PSO’s contradicted readings for 8 July 2009 are real. The PSO archive flags three readings on that date as ones PSO’s own neighbouring notifications contradict: petrol at Rs.50.53 between two notifications of Rs.62.13, kerosene at Rs.52.39 between two of Rs.59.35, and diesel at Rs.53.37 between two of Rs.62.65 — each a move out and straight back within a week.
This document, published independently by the regulator, states exactly Rs.50.53 for petrol and exactly Rs.52.39 for kerosene on 8 July 2009, both rows summing correctly, both with the carbon surcharge at zero for that one week and back at its previous level on the 9th. All four of its products do the same thing. The excursion is genuine published history — a week’s suspension of the levy — and not a corrupted cell. Nothing has been changed on either side; the flag stands, and this is the corroboration a reader of it should have.
For petrol, OGRA’s ex-depot price and PSO’s notified pump price agree exactly on 66 of the 85 dates both cover, and differ on 19. The differences are not random. All 19 fall in 2006–2008, on dates where OGRA restates an unchanged ex-depot price under the price-cap regime of the time, and the gap takes only four values: Rs.2.15 nine times, Rs.2.00 eight times, and Rs.4.00 and Rs.6.00 once each. No claim is made here about which source is right, no figure has been altered on either side, and nothing in the pipeline acts on it. It is recorded because somebody comparing the two files will notice and should not have to wonder whether anyone else did.