Projects

Circular OS

Circular Solutions · Sole engineer · March 2026 to present

Circular OS verifies where commercial recycling actually goes. A property reports what it put out for collection. The hauler and the processing facility each confirm the same load. An administrator signs off the chain.

Recycling numbers are self-reported. A stadium says it kept 60% of its waste out of landfill, that goes in an ESG report, and nobody checks. The two parties who could check are the hauler that took the material and the facility that sorted it. Neither of them is the customer, and neither has any reason to volunteer. I've been the only engineer on this since March 2026.

The unit of work is a verification cycle. It opens on a property, which uploads its own sales data first. Then the system works out which haulers actually serve that address and sends each one only the materials it handles. If it can't tell which hauler took a material, it stops. It won't guess. Facilities answer after the haulers, and nothing gets analysed until everyone has.

The analysis doesn't ask whether the tonnage looks reasonable. It asks whether three parties agree, one material at a time. The property says it recycled glass. The hauler confirms it serves that address, confirms it takes glass, and says what condition the glass turned up in. The facility's capability record says whether it processes glass at all. Any disagreement is a named conflict and the cycle fails: this hauler doesn't serve this property, this hauler doesn't collect this material, this facility doesn't process it, the material arrived contaminated.

The bag conflict is the one I'd point at. A property puts its recycling out in bags. The hauler collects the bags. The facility won't open bags, so the load gets landfilled on arrival. Everybody in that chain is telling the truth and the number is still wrong. You only catch it if you're holding all three records at once. Who hauls what changes without anyone mentioning it, so the whole question reopens every ninety days.

Evidence comes in as hauler invoices, weight tickets, bills of lading, sort line audits, processor registers and the property's own sales data. All of it gets read on upload and split into lines. An operator can also just write a statement about what happened. We take it, store it, and never let it count toward a number.

Most of the work is figuring out what a line means. An invoice line might bill 3.2 tons, or four pulls, or two hours of labour. Only the first is a weight and they all look identical in the quantity column. A month is dated by when the material moved, which is printed on the line, not by the invoice date on the front, and every report prints that rule on itself because people ask. Where the extraction isn't confident the line goes back to the property to fix, and their correction is stored as a correction with the machine's original reading beside it. The system learns patterns off those. Nothing it learns gets applied on its own. A learned conversion factor moves reported tonnage, and tonnage is what customers get audited on.

Diversion is diverted weight over diverted plus landfill. What took the time was working out when to refuse to show it.

Diverted tonnage with no landfill tonnage means somebody didn't send the trash manifests. It does not mean the property hit 100%. If the trash got weighed and the recycling only ever got hauled, the arithmetic gives you a clean zero, which is worse than no number at all. Invoices that bill by volume or by pickup frequency have no weight in them anywhere, and we don't estimate one. Each of those blocks the figure and says on screen which one it was.

Same at the line level. Two loads billed at 9.95 and 9.85 tons are a contract minimum showing up in the quantity column, and the pipeline used to spot exactly that, flag it, and count both as landfill anyway. A spreadsheet with a year-to-date row sitting above the rows it totals will double everything. One pickup can arrive twice, billed once as disposal and again as a commodity rebate under a different PO, so loads match on where and when and what and never on the reference number. A weight ticket uploaded next to the invoice that bills it is the same haul counted twice; on one account that was sixty thousand pounds of overlap. I'd rather drop a real haul than count a fake one. Undercounting a customer is fixable and an inflated diversion rate that's already been published isn't.

Contaminated recycling gets moved to landfill, because that's where it went. Capture rate shows nothing instead of zero when a property has sales but no recycling manifests. Recycled content runs on two different bases and every screen has to name which one it's showing. Diversion and capture ship with default targets. Tonnage and carbon don't, and I left those empty on purpose. Scoring a property against a goal nobody set is just making something up.

Seven kinds of organisation use it and they don't get the same product. Haulers aren't tenants at all. They answer a short questionnaire through a signed link and never make an account, which matters because the whole record depends on them and they're the least likely party to sign up for anything. Processing facilities are full tenants. They get capability records the verification engine reads, multiple physical sites, the ability to pull their own customers onto the platform, and a scheduled reporting service they run for those customers under their own logo. No facility screen shows money.

Above the properties sit the portfolio owners. Corporate accounts track purchasing, which is the other half of the loop: what a portfolio bought back as recycled content against what its buildings actually recovered. Enterprise accounts nest inside each other, carry per-role permissions, and separate a property you report on from one you actually operate. Funders are read only. They fund properties out of credit pools and want to know whether it worked. Manufacturers take in recovered material and never file a sales report, so their recycled content can only be stated on the recovered basis, and it's labelled that way on every surface it appears.

What comes out: monthly diversion summaries, diversion certificates, chain of custody reports, grant packets, portfolio roll-ups. Chain of custody counts loads shipped where the diversion summary counts tons processed, so the columns aren't the same. Facilities and properties register their own customers and we send the reports for them, on a schedule, with their branding on it, then tell the sender which of their own obligations are running late. Venues get a live scoreboard during an event, in the venue's timezone, publishable to the customer or to the public on a link they can revoke.

A property can only publish a story to the public feed once its figures are verified. Compliance snapshots are hashed. The audit log can't be updated or deleted by anyone, including through a full database compromise. If a recompute would move a published diversion rate by more than ten points it raises a flag carrying both numbers, so a figure that already went out to a customer can't change quietly.

In progress: extended producer responsibility

Oregon, Colorado, California and Maine have all passed packaging laws that push the cost of packaging back onto whoever put it on the market. Every state runs its own scheme. Different material categories, different fee schedules, different deadlines, none of it on the same timetable.

The data year and the program year are different years. That's the thing people get wrong most often, so we store both. A deadline only shows as a date if somebody recorded where it was published; if a state has announced a month and not a day, it stays a window. California wants four separate returns against one program year and one of them reports on supply from three years earlier.

A producer registers as a legal entity rather than as an account, because that's how the states register them. Brands sit on the entity. Retired brands stay listed, since they still turn up on filings for the years they sold in. Under the reported weight there's a component-level ledger. A bottle is a bottle, a closure and a label, and those are three materials at three rates.

Volumes go in against that state's categories, sixty of them in Oregon, and a blank isn't a zero. The filing gets priced against whatever schedule the state has published and forecast before anything is submitted. Rates are copied onto the forecast when it runs, so it still says what it said after the state revises them. Weight reported against a material with no published rate gets counted and reported as unpriced. We never price it at zero. A silent zero looks exactly like a correct forecast right up until the invoice arrives.

When the invoice does arrive it's reconciled against that forecast and the gap is split into the part caused by rates and the part caused by weights. One is a question for the state, the other is a question for your own data, and telling somebody they were overcharged answers neither. Anything we can't attribute to one side or the other is reported as unattributable. We don't divide it out into a rate we invented.

The return is a questionnaire and the wording is stored exactly as the state published it, because the answer is an attestation against that wording. Sections get handed to whoever owns them and attested separately, and a single question can be passed to somebody else without moving the section, since not knowing something happens at the question level. Two things chase a filing: section owners who haven't finished, and the managers of a filing whose deadline is coming up. The second one exists because a filing where every section is done and there's nobody left to chase is the one that gets forgotten.

The documents tab is mostly there to show the evidence that isn't there yet. No state publishes a required-document list, so that checklist is the producer's own. Once a return is filed it locks, and the only way to change it is an amendment that leaves the original in place. Anything not wired up yet is visibly disabled with the reason sitting on it. On a compliance screen, a control that looks like it works and does nothing is worse than one that says it can't.