Work · 07 of 9

Margo Rubber

B2B export site where contradictions in the source material cannot reach production

Role
Sole engineer (Third Shade Media)
Studio
Third Shade Media Services
Period
Aug to Sep 2026
Status
client
Stack
  • Next.js 16
  • TypeScript
  • Tailwind v4
  • MDX
  • Zod
  • Sanity
  • Neon Postgres
  • Resend
  • Vercel

Measured

MetricValueWindowSource
Caught by build gates, broken links, lists keyed by href, silent-404 SKU pages13 + 23 + 4Aug 2026check-links and check-blocks gates, tracker log 12 to 13 Aug 2026
Enquiry forms wired, across 6 pages to one validated endpoint; two would have posted empty918 Aug 2026check-enquiry gate, 60 assertions

Problem

A B2B export site for a rubber-components manufacturer: eleven product categories with SKU pages, industries, an export map, case studies, resources, legal pages and enquiry forms. The Figma comps disagreed with each other and with the research pack: five different founding years, six export-country counts, three minimum order quantities, three response-time promises, four email addresses, and certifications on the about page that the client does not hold. Shipping any of those wrong would have cost the client credibility with exactly the buyers who check.

The usual answer is to ask the client and wait. The answer here was to make the contradictions impossible to ship, so that the site could be built while the answers arrived. Client work for Third Shade Media; no visuals, live URL to follow when the domain goes up.

From the repository

81Commitsall mine
36,266Lines of code141 source files
7Build gatescheck-*.mts
Counted from margo-website on 2026-09-15, commits 2026-08-12 to 2026-09-15. Source lines only (no vendored, generated or built files). Seven check-*.mts gates run in CI alongside typecheck and lint.

Next.js 16 App Router with Server Components and TypeScript, Tailwind v4, an MDX content pipeline validated by Zod, migrated to Sanity as the content source in September. Neon Postgres for enquiries, Resend for notifications, sharp for blur placeholders. Every image lives in a registry with a required width, height and alt, so layout shift is impossible by type.

Correctness as a build step

ContentMDX + Zod frontmatterFacts registryunknown = nullBuild gateslinks, claims, schema,formsSanityread direct, not CDNNext.js sitestatic, VercelEnquiriesNeon, validate → spam →store → email
If content is wrong, the build fails with the field path. Nothing unverified reaches production.

Typed content. One MDX file per page, one dynamic route per collection, frontmatter validated by Zod with 60- and 160-character SEO budgets. Malformed content fails the build and names the field. The legal pages are structured blocks (paragraph, subheading, list, callout) rather than prose, so a table of contents can never point at a heading that does not exist.

A facts registry with null. Founding year, street address, phone, the person who catches RFQs: every value the source material contradicted is null in one TypeScript file, with the evidence for each candidate written above it. A template that renders a null fact renders nothing. When the client confirmed the email address on 18 August, one line changed and every page followed.

Gates. check:links builds the route set from the page files and the content slugs and fails on any href outside it; on its first run it found 13 broken internal links and 23 lists keyed by href, which React would have silently mis-rendered. check:claims scans every content file for statements the client cannot make and skips a term that is named in order to deny it. check:enquiry holds 60 assertions on the map from nine forms across six pages to eight canonical database columns; it found two forms that would have posted empty. check:schema and check:blocks keep the Sanity schema and the block types in step with the code.

Enquiries. POST /api/enquiry validates, checks a honeypot, a time-to-submit floor and a per-IP rate limit, stores the raw payload as JSON in Postgres, and only then emails and forwards to a webhook seam for the client’s CRM. The durable copy is written before anything unreliable runs.

Try it

The claims gate, with a stand-in registry. Type marketing copy; the gate flags what the registry cannot support and lets through a term that is named in order to deny it.

Claims gatecheck-claims, the mechanism with a stand-in registry
Facts registrynull = blocked
certifications
["ISO 9001:2015"]
foundingYear
null
moq
500 pieces per SKU
capacity
6,000,000 / year
responseSla
1 business day (IST)
A page that renders a null fact renders nothing for it. The gate is the second line: copy that asserts a blocked or wrong fact cannot build.
$ npm run check:claims -- --strict

✗ line 1  "Founded in 2005"
  founding year while null: foundingYear is null in the registry: the source material gave five different years. Blocked until confirmed in writing.

✗ line 1  "60M pieces per year"
  capacity mismatch: Registry capacity is 6 million a year (500,000 a month). The proposal front page said 60M, which is a typo its own expansion section contradicts.

✗ line 1  "MOQ of 100"
  MOQ mismatch: MOQ is 500 pieces per SKU in the registry. One comp shows 100.

✗ line 1  "within 24 hours"
  response promise: The only promise the client can keep is 1 business day (IST). Nothing faster.

✗ line 1  "cutting-edge"
  marketing register: Banned register. The voice is factual-engineer; buyers who check do not trust superlatives.

✗ line 1  "Rated 4.9/5"
  fabricated social proof: Ratings and order counts with no system behind them. Explicitly banned.

2 terms named in order to deny them, skipped: "IATF 16949", "CE marking"

6 hits · exit 1  (build blocked)

The real gate scans every MDX file, exempts the mandatory non-claim blocks (some pages must name a standard in order to deny it), looks at a small window of lines because YAML folds long strings, and lists everything still flagged for the client's written sign-off. It runs with check:links (13 broken hrefs and 23 lists keyed by href on first run), check:enquiry (60 assertions on the form-field map; two forms would have posted empty) and check:schema.

Timeline

  1. Comp audit against the research pack five founding years, six export-country counts, three MOQs, three SLAs.
  2. Content pipeline, case studies, resources, 404 and the React key collision fixed by keying lists by label.
  3. SKU pages: 31 anchors, 29 legacy URLs mapped four silent 404s found: a missing collection case, YAML null, an SEO budget, an h1 rule rejecting "C Pad".
  4. Motion tokens; pinned trade-lane sequence on /export CSS scroll-driven timelines, no library, no client boundary.
  5. Email confirmed by the client; footer as content; brand typography
  6. Enquiry pipeline: schema, endpoint, nine forms wired the 60-assertion field-map gate lands.
  7. Two new categories, mega-dropdown, brand-rule audit 3 of 6 rules were failing; fixed across 18 buttons that bypassed the Button component.
  8. Sanity as the content source read direct rather than through the edge CDN after stale reads; signed publish webhook.
  9. One image slot per placement nothing on the site shares a photograph; a verify script tests the rule.
From the git log and the daily tracker.

Before and after

BeforeAfter
Contradictory factsWhichever comp the developer copied fromOne facts registry; unconfirmed values are null and render as nothing; a forbidden-claims list
Broken linksFound by visitors13 broken hrefs and 23 lists keyed by href caught by a build gate
SKU pagesFour silent 404s from a missing collection case, YAML null, an SEO budget and an h1 length rule rejecting "C Pad"All rendered; 29 legacy WooCommerce URLs mapped with 301s
Enquiry formsNine forms on six pages, two would have posted emptyOne endpoint, eight canonical columns, honeypot and time-to-submit, a 60-assertion field-map test
Content editsA developer and a deploySanity Studio at /studio, signed webhook revalidation, read direct so an edit is live in seconds
MotionAnimation library for the export mapCSS scroll-driven timeline, no JS, no client boundary

Judgment calls

I declined to draft legal copy and left those pages as structured blocks for the client’s counsel. Founding year and export counts stayed null until the client confirmed them, and the site shipped without them rather than with a guess. A capacity figure on the proposal’s front page was ten times the figure in its own expansion section; the gate bans the larger one. Where the comps invented certifications, the certifications page states plainly what is held, and the gate makes sure nothing else claims more.

Learned: Hold unknown facts as null, never guess. A build gate is cheaper than an apology.

keysKeyboard
j / k
next / previous row
Enter
open the focused row
⌘K or /
search, or ask this site
g then h w a c
go home, work, about, contact
t
toggle light and dark
Esc
close the palette or this map
?
this map