TraplineBuild notes

Generative Assets · Industry demos · Site 407

How the Trapline Trade Waste page was made

A grease arrestor is sold on two numbers a customer cannot pace out: how deep the tank has to sit before its outlet can still fall into the sewer, and how many weeks it takes the grease to reach the quarter-full line. This page draws both, to scale, on a fixed three-metre axis — and refuses the job three different ways when the honest answer is no.

The concept

Trapline Trade Waste is a fictional Welshpool business that supplies, installs and pumps out grease arrestors for Perth kitchens. Its customers are restaurateurs three weeks from opening, cafe owners who suspect they have been oversold, and charcoal shops whose arrestor overflows every ten weeks. The page has one job: turn “what size grease trap do I need” into a booked site measure — with the capacity, the tank, the pump-out cycle and the yearly running cost already on the screen.

The signature is The Section: a true-scale SVG cross-section of the tank sunk into the ground, against a fixed 0–3,000 mm depth axis that never rescales. The fixed axis is the argument — every arrestor in the catalogue sits between 1,200 mm and 2,700 mm deep, so holding the axis still lets a customer compare two tanks by eye, which is the decision they are actually making. The smallest tank occupies 40 % of the axis; the largest occupies 90 %.

Palette

Argued from what is actually in a grease arrestor: precast concrete, Perth sand, grey water, floating grease and settled solids. Every ratio below was computed with WCAG arithmetic from the shipped hex (contrast-greasetrap.mjs), not estimated, and each token declares the grounds it is used on. A token drawn on a ground outside its used-on list is a defect even if it looks fine.

#F3F1ECstone paper — page ground, the colour of a commercial kitchen floor tile
#FFFFFFcard ground
#1A1E1Cink — body copy, every scene label, primary button
#565A55muted ink (derived) — eyebrows, captions, ledger labels
#77590Egold ink — grease figures, the grease band’s outline
#186B68drain teal — flow lines, invert lines, secondary button
#A33A2Erefusal red — the three refusal panels and the shortfall dimension
#CFC5B2soil fill
#C3C0B8tank concrete fill
#9FBFBEstanding water fill
#E0C36Afloating grease fill
#9C8A76settled solids fill
TokenHexUsed on (measured)Forbidden grounds
Ink — body and every scene label#1A1E1C paper 14.93 · card 16.85 · hairline 12.20 · wash 13.92 · soil 9.85 · concrete 9.27 · water 8.56 · grease 9.78 · solids 5.06 none
Muted ink (derived here)#565A55 paper 6.22 · card 7.02 · wash 5.80 soil 4.11 · concrete 3.86 · water 3.57 · grease 4.08 · solids 2.11
Gold ink#77590E paper 5.78 · card 6.52 · wash 5.39 hairline 4.72 · soil 3.81 · concrete 3.59 · water 3.31 · grease 3.78 · solids 1.96
Drain teal (text)#186B68 paper 5.57 · card 6.28 · wash 5.19 hairline 4.55 · water 3.19 · solids 1.89
Drain teal (lines, 3:1 bar)#186B68 soil 3.68 · concrete 3.46 · grease 3.65 water 3.19 · solids 1.89
Refusal red (text)#A33A2E paper 5.81 · card 6.56 · wash 5.42 hairline 4.75 · water 3.33 · grease 3.81 · solids 1.97
Refusal red (lines, 3:1 bar)#A33A2E soil 3.84 · concrete 3.61 water 3.33 · grease 3.81 · solids 1.97
Grease-band edge (line only)#77590E grease 3.78 everything else — it is the one line drawn on the grease
Sticky-bar ink on ink ground#F3F1EC on #1A1E1C14.93
Buttons#1A1E1C / #186B68white labels 16.85 / 6.28

34 of 34 used-on rows pass (text at 4.5:1, graphical lines at 3:1). Two notes on the palette. The gold ink was darkened at spec time from #8A6A12, which measured 4.48:1 on this paper — a miss by 0.02. And the settled-solids fill was lightened from #7A6857 (3.17:1 against the body ink, a fail) to #9C8A76 (5.06:1), because a settled-solids band is exactly the thing that needs a depth label written across it. Neither fill was re-tinted by this build; both remedies were pinned before it started.

The muted ink #565A55 is derived here — the concept pinned no caption token — and it is deliberately a paper-and-card-only text colour. It never labels the drawing. The drawing gets exactly one text colour, the body ink, so nothing on the artwork reads as secondary.

Type

Bricolage Grotesque at 600 and 700 carries the display. It is a contemporary grotesque with just enough irregularity in the curves to read as workshop rather than agency — which is the register a plumbing contractor wants. Inter at 400/500/600 is the workhorse; Roboto Mono carries every litre, week, kilogram and millimetre, because a number that stands still under a stepper tap is a number you can trust.

Body is 17px on mobile and 18px from 900px up. The typographic bravery is the pump-out interval: a single enormous numeral with WEEKS BETWEEN PUMP-OUTS tucked under its shoulder in 0.78rem caps at 0.11em tracking, changing live as the kitchen chips move. In a refusal state that numeral shrinks and turns red and stops being a number at all — it reads Levels first or None.

The signature: how The Section is drawn

One inline SVG, no libraries, held in millimetres and laid out in real CSS pixels per width — the viewBox is recomputed from the container’s measured width on every draw, so a 10.5px label is 10.5px at 375 and at 1440. A fixed viewBox would have rendered the dimension text at about 4px on a phone.

The vertical map is y(mm) = yLid + mm × scale, where scale = sceneWidth / (leftMargin + tankWidth + rightMargin) in millimetres. The axis always spans 0–3,000 mm below the datum, whatever the tank. Horizontally the frame is proportional to the tank’s own width, so a 10,000 L slab reads visibly wider than a 1,000 L box.

The three layers, and the rule they are measured against

The standing water level is set by the outlet invert, which is physically true: the liquid in an arrestor sits at whatever height the outlet lets it sit. Grease grows down from that line, settled solids grow up from the floor slab. The hard dashed rule is drawn at 25 % of the wet depth below the water line, and the gauge is the sum of the two accumulations, not either one alone — which is what the servicing rule actually says.

Because grease and solids grow from opposite ends, a single rule cannot be read directly. So the drawing carries a hatched block immediately under the grease band whose height equals the settled-solids depth: the solids, carried up so the sum lands on the rule. That is the second-read detail. The caption under the scene says so in one sentence rather than leaving it to be guessed.

Second second-read: a faint dashed ghost of the 10,000 L tank (or the 2,000 L, when the arrestor is going inside a tenancy) sits behind the current one. It fills what would otherwise be an empty band of soil, and it is the whole reason the axis is fixed — you are looking at two tanks at once.

The inside-the-tenancy flip

An above-ground unit is not a sunk tank drawn differently; it is a different drawing. When the location chip is Inside the tenancy the datum moves to the bottom of the axis and becomes a tenancy floor, the tank stands on it, the axis counts upward, the soil hatch becomes a slab, and the sewer invert line is not drawn at all — because it stops applying. The sewer invert chips disable themselves with an on-page reason and remember your last choice for when you switch back.

Motion

The fill runs once, from week zero to the pinned pump-out week, over 4.5 seconds, and stops. It has to finish before the 7-second thumbnail instant, because the frame the collection captures should be the argument the page makes: the grease band and the settled solids together meeting the quarter-full rule at week 14 of 14, which is the whole reason the truck comes. Measured cold-load settle is about 5.1 s from navigation — roughly two seconds of margin — and because the fraction comes from elapsed time rather than frame count, a 20× CPU throttle leaves the fill length unchanged at 4.2 s. The entrance is gated on a cold-load flag; a resize rebuilds the geometry and never re-enters it, because taking a clipped screenshot changes device metrics and therefore fires the resize handler. Changing a chip does not restart the fill either: the fill fraction is the scene’s clock, so swapping the kitchen redraws the same point in a different cycle, which is the honest reading. Under prefers-reduced-motion the scene is drawn at that same end state immediately.

The fill was driven by frame count, and headless Chrome starved it

The first implementation accumulated a per-frame delta with the standard 50 ms cap. Headless Chrome services requestAnimationFrame only when something asks for a frame, so at the 7-second thumbnail instant the tank had reached 2.5 % of full — an essentially empty tank in the captured preview, while every state assert stayed green. The thumbnail pipeline uses the same renderer, so this would have shipped. The fill is now driven by wall clock: a 50 ms timer sets the fraction from elapsed time, and the timer only decides when to repaint. The probe’s fillT is refreshed by the ticker rather than by the last render, because the first fix looked like it had failed when only the probe was stale.

Wall clock fixed the starvation but not the duration

With the fill correct but running for ten seconds, the 7-second capture landed at week 9 of 14 — a handsome frame, and an accident. The page never satisfied the collection’s “comes to rest visible” rule: settled was still false at 7 s and fillT was still moving 8 s later. Reaching the end state is not a concession to the harness; the sum of grease and settled solids touching the quarter-full rule is the only frame that shows why the truck comes at all. Ten seconds is a slower fill that ships a weaker picture. The duration came to 4.5 s and reduced motion, which had been settling to an arbitrary 75 % frame, now draws the same end state the fill arrives at.

The model

Sizing

The way the plumbers size it, and the way the permit application asks for it:

  • Daily flow = covers a day × litres a cover (12 cafe · 15 bakery · 20 a la carte · 26 charcoal).
  • Required capacity = ceil(daily × 2 / 5) — the arrestor holds the peak two-hour discharge.
  • The tank is the smallest legal catalogue size at or above that figure. Legal means it fits the location’s cap and, in the ground, its outlet invert can still fall into your sewer.

Pump-out cycle

  • Grease = ceil(covers × grams × days / 1000) kg a week (18 · 22 · 30 · 55 grams a cover).
  • Weeks to the quarter-full line = floor(capacity × 25 / 100 / kgPerWeek), at least 1.
  • Pump-outs a year = ceil(52 / weeks); the yearly cost is that count × the size’s pump-out rate.

Two modelling simplifications are declared here rather than buried. The 25 % budget is held in litres treated as kilograms, which overstates the budget by roughly the density of grease; and the interval is computed from the grease load alone, with the settled-solids share folded into it. The drawing then splits the accumulation two parts grease to one part solids, which is what these tanks look like when you open them. None of this changes the honest headline, which is on the page in the cycle card: the interval is an estimate from a typical grease load, we open the arrestor and check it, and your permit may set a maximum interval whatever the load says.

Money

Every rate in the model is a whole dollar by construction, so every total is a whole dollar and Number.isInteger is an invariant rather than a rounding decision. The price function throws if any field it returns is not an integer, and the harness asserts it on every driven vector.

SizeSupply & installPump-outOutlet invertDrawn depth
1,000 L$3,900$330350 mm1,200 mm
1,500 L$4,800$390400 mm1,350 mm
2,000 L$5,900$460450 mm1,500 mm
3,000 L$7,600$580500 mm1,750 mm
5,000 L$11,400$780600 mm2,100 mm
7,500 L$15,900$1,050700 mm2,400 mm
10,000 L$20,800$1,290800 mm2,700 mm

Plus location (+$0 / +$2,400 restricted / +$1,650 inside), drain alteration at $145 a metre, reinstatement (+$0 / +$890 asphalt / +$1,240 concrete), the sampling point and sign-off at $480 and the permit application assistance at $390. The $5,500 minimum is a floor on the whole job, never an addition — every line sits inside it, and the ledger says so in both directions (when it binds and when it does not).

The three refusals

This site carries the most refusals in the wave, and none of them prints a dollar figure anywhere — not in the badge, not in the hero total, not in the ledger, not in the cycle card, not in the plain-text mirror. The harness asserts the absence of a $ across all of those surfaces in each refusal state.

  1. Coffee and pre-packaged only — 85,050 enumerated cells. The drawing loses the tank entirely: a sink and a basket strainer above ground, and a dashed red outline in the soil where an arrestor would have gone. “We’d rather tell you that now than sell you a tank.”
  2. Required capacity over 10,000 L — 17,010 cells. The biggest arrestor we install is drawn with a red dashed outline and the required figure written above it. At 1,200 covers of charcoal that is 12,480 L, and the answer is a pre-treatment plant designed on site.
  3. The tank cannot reach the sewer, or will not fit the location — 152,523 cells. The needed tank is drawn where it would go, and the shortfall is dimensioned in refusal red: at 600 covers of charcoal on a 450 mm sewer, the 7,500 L outlet sits 250 mm below the connection. That gap is a pump station, and it is why we shoot levels before we quote.

Verification

Three independent implementations of the same model were written for this build: the wave’s own oracle-w50.mjs, an independent reimplementation from the concept prose (oracle-greasetrap.mjs, 88/88), and a third compact one inside the headless harness (verify-greasetrap.mjs, 209/209) so the page is never checked against its own arithmetic.

EnumerationResult
Grid cells / priced cells425,250 / 170,667
Non-integer priced cells0
Cells where the $5,500 minimum binds210
Cells where the headroom chip is forced back down43,533
Refusal 1 / 2 / 3 cells85,050 / 17,010 / 152,523
Cheapest total (= the services-grid floor)$5,500
Cheapest subtotal, unclamped$5,350
Dearest total$27,260
Shortest pump-out cycle on the grid6 weeks
Longest pump-out cycle on the grid125 weeks (displayed capped at 52)
Dearest pump-out year$11,610
Trading-days chip: comparable vectors / price disagreements / cycle moves18,963 / 0 / 18,018

The trading-days claim is the one price-neutrality statement on the page, and it holds under its stated held-equal condition: the chip enters no install line in any of 18,963 comparable vectors, and it moves the pump-out cycle in 18,018 of them. It is neutral, not inert, and the page says exactly that.

Where this build disagreed with its brief

The standing instruction is to re-derive every figure in an independent oracle, ship the reading that reproduces the pinned endpoints, and report the disagreement rather than silently changing either side. Seven disagreements were found. None was resolved quietly.

1. The pinned rest state is not reachable on the pinned stepper

The concept’s rest scenario — the thumbnail, the whole above-the-fold argument — is “a 300-meal a la carte restaurant”. The meals stepper is pinned at 40–1,200 in steps of 40, thirty values, and 300 is not a multiple of 40. The cell is arithmetically correct and permanently unreachable.

Changing the stepper would have invalidated every enumerated count in the document (425,250 = 30 × 5 × 3 × 3 × 5 × 7 × 3 × 3), so the stepper stands and the rest vector moved to the neighbour that reproduces the most pinned endpoints. Both neighbours were enumerated:

CoversRequiredTankkg/wkWeeks/yearRunningInstall
300 (unreachable)2,400 L3,000 L54 kg134$2,320$11,100
280 (shipped)2,240 L3,000 L51 kg144$2,320$11,100
3202,560 L3,000 L58 kg125$2,900$11,100

280 covers ships. It reproduces the pinned arrestor size, the pinned four pump-outs a year, the pinned $2,320 running year and the pinned $11,100 install exactly — every endpoint the wave’s own consolidation sweep asserts. Three intermediates move and are printed as measured: required capacity 2,240 L (not 2,400), grease 51 kg a week (not 54), and the interval 14 weeks (not 13). At 320 covers the running year would have moved to $2,900, which is why 280 rather than 320.

2. The refusal-3 attribution split is a labelling convention, not a measurement

The concept splits refusal 3 into 24,003 sewer and 128,520 location. That split comes from asking only whether the location has a cap at all — so a restricted-access job that a 5,000 L tank would happily fit, blocked purely by a 450 mm sewer, is counted as a location refusal.

Asking instead which constraint actually binds — would this tank have fitted on the location cap alone? — gives 32,508 sewer / 120,015 location. The union is identical at 152,523, so no reachability claim moves. The page uses the binding attribution, because the refusal names a constraint to the customer and naming the wrong one would send them to fix the wrong thing. The 8,505-cell difference is exactly the set where a capped location and a shallow sewer both bite.

3 & 4. Two pinned strings were missing their pinned text

The wave rule is that every badge-surface string carries a pinned form and a pinned ≤640px short form, so five builders do not each invent one. Two were absent for this site and are declared here as this build’s own:

  • The forced-headroom note. The concept’s chain step 4 says only “upsizeForced true, note renders”. Shipped: “the sewer at {invert} mm caps this job at {size} L — we’ve held your headroom there”, with “{location} caps this job at {size} L — we’ve held your headroom there” when the location is what binds; short form “headroom held at {size} L”.
  • The location variant’s short form for refusal 3. The sewer variant is pinned (“Sewer’s too shallow for this tank — that’s a pump station.”); the location variant is pinned only in its long form. Shipped short form: “Won’t fit where you want it — that’s a site visit.”

5. This site settles one-shot, and the wave preamble does not say so

The preamble names coolroom and mezzanine as the two sites that settle one-shot by design, and warns that a passive pixel-diff or mutation-count liveness probe will read them as dead. This site’s own section pins “the fill animation runs to the pinned pump-out week and stops” — which is the same shape. It is flagged here so wave QA drives a control before calling the page dead: the drive-then-diff tier is not optional for this slug either.

6 & 7. Two smaller ones, both in the wave oracle rather than the prose

  • The drawn depth of each tank is not in the concept prose at all — only the extremes survive, implied by the axis-fraction claim (1,200 mm = 40 % and 2,700 mm = 90 % of a 3,000 mm axis). The intermediate depths in the table above were taken from the wave oracle’s own size table, and both extremes were re-asserted.
  • The wave oracle’s code comment says a size is legal when its outlet invert, “300 mm above the base”, reaches the sewer. That is stale from the draft the concept itself describes as fixed: on the pinned figures a 1,000 L tank is 1,200 mm deep with a 350 mm outlet, which is 850 mm above the base, near the lid — which is where a real arrestor’s outlet sits. The pinned per-size outlet table is what this build implements; the comment is simply out of date.

Three conventions this build had to invent, declared

  • The 2:1 grease-to-solids split of the drawn accumulation. The model tracks grease only; the drawing has to show two bands. Two parts grease to one part solids is what these tanks look like opened, and it is a drawing convention, not a measurement.
  • The 25 % budget in litres treated as kilograms, which is the plumber’s rule of thumb the model inherits. It overstates the budget slightly, in the customer’s favour on interval and against us on truck visits, and it is why the page insists the arrestor gets opened and checked.
  • The emergency overflow attendance floor of $690 after hours. The conversion checklist pins six services; this is the one with no pinned floor. $690 is plausible for a WA after-hours vacuum-truck callout and is not reachable from the estimator, so it cannot contradict it.

On the real regulation, which outranks the spec

Nothing in the concept misstates the three real things this page leans on. The Water Corporation industrial waste permit is genuinely what a Perth food business needs to discharge trade waste to sewer, and the permit officer genuinely sets the required pre-treatment — the pinned honesty line is correct and appears wherever the capacity does. AS/NZS 3500.2 is correctly named for sanitary plumbing and drainage. Grease trap waste is genuinely a controlled waste in Western Australia, so a DWER-licensed carrier and a tracked load are the honest description of a pump-out.

One nuance was added rather than corrected: a permit commonly sets a maximum service interval regardless of load. The model computes an interval from grease alone, and its longest reachable cell is 125 weeks. Shipping that without a caveat would have implied the load alone decides, so the cycle card carries the line — “your permit may also set a maximum interval whatever the load says, and if it does, that interval wins” — alongside the concept’s own pinned over-a-year note.

The iteration log

  1. Pass 1 — Craft. The 375px masthead was checked before anything else: the wordmark’s right edge clears the call button’s left edge, but the call button itself measured 42px tall, under the 44px tap-target floor — .btn-sm went to 44. At 1200 the headline ran five lines and pushed the “this kitchen, installed” card out of the thumbnail; the copy was cut and the display clamp came down from clamp(2.5rem, 4.4vw, 3.5rem) to clamp(2.1rem, 3.5vw, 2.85rem). The scene header printed a scale ratio, “1 : 6” — which is meaningless, because a screen pixel is not a physical unit, so it was a false claim in a caption; replaced with fixed 0–3 m axis, which is the honest and more useful statement. The tank-depth dimension label was clipped by the left gutter at both 1200 and 375, and the quarter-full caption sat on top of the hatched solids block; the first moved above its arrow, the second below its rule.
  2. Pass 2 — Depth. The band of soil below the tank was dead space that the fixed axis creates by design, so it earned the second read: a faint dashed ghost of the 10,000 L tank (or the 2,000 L, inside a tenancy) now sits behind the current one, which is the entire reason the axis does not rescale. The soil got a deterministic Perth-sand stipple — a seeded LCG rather than Math.random, so the 7-second thumbnail is identical on every capture. The inside-the-tenancy flip was built out properly: the datum moves to the bottom of the axis, the axis counts upward, the soil becomes a slab and the sewer chips disable with a reason and a remembered value. Refused tanks are now drawn standing empty, the scene caption became state-aware (four variants), and the ledger’s refusal state got its own heading and line instead of an empty card. At 375 the drawing shed five labels and moved the outlet/sewer pair to one centred caption under the tank — the phone gets the same drawing with less shouting.
  3. Pass 3 — Hardening. Four real defects, three of them invisible to every assert.
    • The fill was frame-driven and headless Chrome starved it — 2.5 % full at the thumbnail instant. Rewritten to wall-clock; see the note above. This one would have shipped an empty tank as the preview image.
    • A class collision. The site footer and the ledger’s footnote both used .foot, so the footnote inherited the footer’s padding: 34px 0 120px and left a dead 120px hole inside a card. Renamed .pagefoot.
    • .svc p{flex:1} also matched p.from, so the price line shared the free space instead of being pushed to the bottom of the card and the six floors did not align across a row.
    • A review argued with the model. “Pumping the old 1,000 out every five weeks … we are on fourteen weeks now” on a 5,000 L is not a reachable pair: 14 weeks on a 5,000 implies about 86 kg of grease a week, which on a 1,000 L is two weeks, not five. Rewritten to every fortnight, and “half what a charcoal kitchen needs” corrected to a fifth, because 1,000 to 5,000 is a fifth.
    Also: the service-area map drew Rockingham outside the dashed boundary the copy claims to cover, and Victoria Park’s label sat 150 units from its dot with no leader — both fixed. The FREEBOARD caption was removed under the Chanel rule: it named something the drawing already says and made a fourth label in a tank with room for three. Keyboard drive added to the harness (Enter on a chip, Enter on a stepper, focus on an FAQ summary, a measured focus ring); reduced motion settles to a visible mid-cycle frame; and both pages were scanned for a word character followed by = and a typographic double quote — zero hits, on the site and on this guide, which is where all twenty-one of last wave’s shipped.
  4. Pass 4 — Landing it. The wall-clock rewrite in pass 3 fixed how the tank filled but left how long alone, so the fill was still climbing at the 7-second capture: settled false, fillT still moving eight seconds later, and a thumbnail reading “week 9 of 14” that looked deliberate and was not. The fill duration came from ten seconds to 4.5, which puts the settle at about 5.1 s from navigation and makes the captured frame the designed one — grease plus settled solids meeting the quarter-full rule at the pinned pump-out week. Reduced motion had been settling to an arbitrary fillT = 0.75; it now draws that same end frame. Re-verified: settle unchanged at 4.2 s of fill under a 20× CPU throttle, no numeric probe field moving in the eight seconds after the capture instant, every chip and both steppers, the force and partial-unwind chain, all three refusals, a 240-click rapid-fire drive, empty and filled submits, a clipped screenshot and a real viewport resize with the scene staying settled and opaque, and both pages re-scanned for a word character followed by = and a typographic double quote — still zero hits.

Conversion decisions

Why the drawing sits below the copy on a phone

At 1200 the section and its price badge share the fold with the headline, because the 1200×750 preview is the commercial argument. At 375 they do not: a customer standing in a kitchen with a landlord on the phone needs the business name, the promise, a call button and a trust signal before anything else, and the drawing is a scroll away. The rest total prints in both the hero column and the on-scene badge, so the fold assert is satisfied with margin rather than by luck.

Why the form asks for meals a day

Name, phone, venue suburb, kitchen type, covers a day, message. The first three are the callback; the middle two are the entire sizing model. Asking for covers a day means the yard rings back already holding a tank size instead of starting from scratch, which is the difference between a quote call and a discovery call.

Why the estimator does not pre-fill the form

The usual pattern is to hand the signature’s scenario into the enquiry fields. This page deliberately does not, for two reasons. A pre-filled form makes an “empty” submit partially valid, which quietly hides whether the validation works at all; and a visitor who never touched the estimator should not find a stranger’s scenario in their own enquiry. The handoff runs the other way instead: the confirmation panel recaps whatever the section is currently showing, refusal included, so the lead carries the context without the form pretending it was filled in.

Why the confirmation is local, and says so

No network round-trip is faked. The panel appears only after a genuinely valid submit, is hidden on load and on an empty submit, and its second sentence states plainly that nothing is sent anywhere because there is no server behind this form. The callback promise beside the form is static copy and is deliberately not the confirmation.

Why the services grid floors are enumerated, not written

The first card reads from $5,500, and that is the same number as the cheapest output the estimator can produce over its whole 425,250-cell grid — 40 covers of cafe, five days, clear access, four metres of drain, gravel: a $5,350 subtotal that the minimum lifts to $5,500. A page whose calculator undercuts its own price list argues with itself, so it was enumerated rather than asserted.

Local SEO we would implement for the real business

This page emits no business-shaped structured data. Its live JSON-LD is limited to WebPage, WebSite, CreativeWork and a BreadcrumbList, and the WebPage description names it a demonstration — because publishing a fictional business as LocalBusiness, with fictional reviews and a fictional aggregate rating, is dishonest markup in a real index.

For the real Trapline — a real ABN, a real licence number, real reviews with consent — this is what would ship. The correct organization type for a plumbing contractor is Plumber, a genuine LocalBusiness subtype, not a service or specialty token.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Plumber",
  "@id": "https://trapline.com.au/#business",
  "name": "Trapline Trade Waste",
  "description": "Grease arrestor supply, installation and scheduled pump-outs for
                  Perth commercial kitchens.",
  "url": "https://trapline.com.au/",
  "telephone": "+61 8 XXXX XXXX",
  "priceRange": "$$",
  "image": "https://trapline.com.au/img/yard.jpg",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "REAL STREET ADDRESS",
    "addressLocality": "Welshpool",
    "addressRegion": "WA",
    "postalCode": "6106",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -31.99, "longitude": 115.94 },
  "areaServed": [
    { "@type": "City", "name": "Perth" },
    { "@type": "AdministrativeArea", "name": "Perth metropolitan area" }
  ],
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "06:30", "closes": "16:00"
  }],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Trade waste services",
    "itemListElement": [
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Grease arrestor supply and installation" },
        "priceSpecification": {
          "@type": "PriceSpecification", "minPrice": 5500, "priceCurrency": "AUD"
        } },
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Scheduled grease arrestor pump-out" },
        "priceSpecification": {
          "@type": "PriceSpecification", "minPrice": 330, "priceCurrency": "AUD"
        } }
    ]
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.8", "reviewCount": "63"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "REAL REVIEWER, WITH CONSENT" },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "REAL REVIEW TEXT, SYNDICATED FROM THE REVIEW PLATFORM"
  }]
}
</script>

Alongside it: a Google Business Profile with the yard’s real address and service-area radius, an FAQPage block built from the six questions already on the page (they are the ones the yard is actually asked), and suburb landing pages only where there is real service history to write about — never a generated set.

What would change for the real client

A grease arrestor business is a route business. The install is the acquisition; the schedule is the product. So the integration that matters is not the enquiry form — it is the recurring job.

  • ServiceM8 or Simpro for the pump-out schedule. Every installed arrestor becomes a recurring job with the size, the outlet depth, the access notes and the last measured grease depth attached, and the enquiry form posts straight into the job list rather than into an inbox. Simpro if there is a stores and asset side to run; ServiceM8 if the yard lives on phones.
  • The docket flow. Controlled-waste tracking is a legal artefact, not paperwork — the driver’s completed job should attach the tracking form and email the customer the same day, automatically. That is the single most valuable thing this business can automate, and it is also its best retention tool.
  • The estimator becomes a lead scorer. Every submitted vector is a sized job. Piped into the CRM it tells the yard which enquiries are 10,000 L pre-treatment referrals to hand on, which are $5,500 minimum jobs, and which are the coffee shops to be honest with in thirty seconds.
  • Their photos and their reviews. Every drawing here is procedural, which proves the design carries without stock photography — but a real Trapline has an excavator over a hole and a truck with a hose, and those go in. Reviews come from a live feed with consent, at which point the schema above earns its aggregateRating.
  • The permit application. Pre-filling the Water Corporation industrial waste permit application from the site measure is the highest-value piece of admin removal in the whole business, and it is exactly the kind of manual bottleneck we build for.

Trapline Trade Waste is a fictional business — a grease arrestor industry demonstration designed & built by Sapience Analytics, part of the Generative Assets collection. The phone number, ABN and plumbing licence string are reserved placeholder patterns and the suburbs are used at suburb level only. The Water Corporation industrial waste permit, AS/NZS 3500.2, the DWER controlled-waste carrier licence and the quarter-full servicing rule named on these pages are real; the prices, the catalogue and the reviews are demonstration copy.