FERNWAY

Changelog

Every change, as it shipped.

Read from Fernway’s own commits, newest first, with the moment each one went live. 64 changes so far.

Tuesday, 10 November 2026

  1. 31

    715b74aDeployed 15:27 UTC

    Status: live parts, delivery queue, GHL answer times and backups, from real data only

    • Migration 0007: scans.answer_ms (every GHL call timed; test failed first) and ops_runs, written by the deploy, the nightly backup, its off-box copy and the restore test as the database owner; the app can only read it.
    • statusView: the queue, 24 h signed/held/returned, GHL calls with typical and slow answer times, the latest run of each kind; the demo account is left out. Tests prove the numbers agree and nothing is invented on an empty system.
    • /status: parts board, deliveries, GHL, backups (failed or late in the held amber only), checked again every 30 s.
    • Shared useNow clock and Ago component; CI checks the runs reach the page, a failed restore shows as Failed.
  2. 32

    7b44422

    How delivery works: proof links open the test's own line, and the build checks every line

    • GitHub's code view ignores text fragments, so a proof link opened the file but not the test. Each proof now names its line (engine.test.ts:115, linked as #L115) and proofs.test.ts fails the build when a test moves off its line.
  3. 33

    1d84138

    How delivery works: each GHL failure, what Fernway does, and the tests that prove it

    • /delivery: six cases (rate limit, busy or down, a refusal waiting won't fix, a token running out, the same lead twice, a crash in the middle), each with the named tests, linked to their place in the code.
    • packages/delivery/test/proofs.test.ts fails the build if a named test stops matching its file.
    • The retry clock is one shared component, its tries read from the engine's own schedule; the landing uses it.
    • Linked from the landing's retry clock and the footer; CI checks the page and that it sets no cookie.
    • Docs: answers wrap at every size instead of scrolling sideways.
  4. 34

    68b7beb

    Docs: glyph on every link, live status in Run it, numbered tables and lists, facts not orders, phone layout

    • Rail, section jumps and in-text links carry their own glyphs (play, brackets, jump).
    • Run it here says what it is doing while it works.
    • Every table has a # column; the state and scan lists are numbered.
    • Answer texts in the OpenAPI document and the docs state facts instead of giving orders.
    • On a phone the rail keeps only the two pages and code wraps instead of hiding its end.
  5. 35

    16e2bc4

    Docs and the API: keys, POST and GET /api/v1/leads, OpenAPI, quick start

    • API keys: migration 0006, stored as a SHA-256 hash, shown once; CLI apikey, apikeys, revoke-apikey.
    • POST /api/v1/leads and GET /api/v1/leads/{number}: bearer key, idempotency, 60 a minute per key; the public docs key reaches only the demo account and is limited per visitor.
    • The OpenAPI 3.1 file and the reference are generated from the same zod schemas the API answers with.
    • /docs quick start runs the same request from the page; /docs/api reads the OpenAPI document.
    • Demo-account leads with no failure in their key pass the stand-in first try.
    • Receipts name API leads as "Your code" and demo leads as going to the stand-in GHL.
    • CI proves the API end to end, including that the docs' key never reaches a GHL.
  6. 36

    32dc42b

    Landing: the first screen fills the window only up to its content's height

    • At 25% zoom (Jerome) the first screen stretched to the whole, now huge, window and left a tall empty band of background before the sections. It now fills the window up to 1000 px (its content needs about 975) and stops. Measured: at 25% and 33% the sections start right under the strip; at 1920, 1440 and 1366 the first screen still fills the window exactly.
  7. 37

    838ad16

    CI: the restore check compares every table with its live count, not a fixed number

  8. 38

    9c9961a

    Fake GHL: asking it what it was asked is not counted as a GHL call

  9. 39

    5b0a959

    CI: name the calls if Break it ever reaches a GHL

  10. 40

    3a70308

    CI: trace the Break it step's commands

  11. 41

    07dcf5c

    Receipts: the hold reason reads as words too, not GHL's raw JSON

  12. 42

    23d0db7

    Break it: make GHL fail on purpose and watch Fernway deliver the lead anyway

    • The real engine and queue against a stand-in GHL inside Fernway (breakit.ts), on the demo account only, with the 24 h retry clock sped up 10 times and the page saying both. Six failures: 429, 503 twice, no answer (a real 1 s silence, the 10 s timeout sped up), an expired token, bad data held until the visitor resends it, and the same lead sent twice. The lead is invented; nothing about the visitor is sent. Receipts now say why a try is re-sent and show GHL's refusal as words, not JSON. Break it leads go after a day. CI runs it on the real stack and proves none of its calls leave Fernway.
  13. 43

    df49566

    Queue: a resend or a re-queued try runs, instead of being dropped as a duplicate

    • The queue keeps finished jobs, and BullMQ ignores a new job whose id it still holds. A resend starts again at try 1 (s<id>-t1) and the sweep re-queues a stalled try under its own id, so both were silently dropped: a resent lead sat picked up for ever. Now a try whose old job finished or failed has that job cleared first; a try still waiting keeps its job, so none is queued twice.
    • Proven on real Redis: the new test failed on the old code.
  14. 44

    dad0a27

    Privacy, Terms and About: what Fernway keeps, what it is, who built it

    • Privacy says exactly what the code does: the form fields kept, delivered into Fernway's demo GoHighLevel account, removed after 30 days from GoHighLevel first, backups, the hour-long per-IP counts, no cookies, and how to have a lead removed sooner. Terms: a portfolio product, what the forms do and don't do.
    • About: what is real, what is only a demo, built and run by Jerome Badour. The forms' 30-day line links to Privacy. CI checks no public page sets a cookie.
  15. 45

    85462d7

    Book a demo: the day buttons wrap instead of running off the edge

Deploys are recorded from the first deploy after the status page shipped; earlier changes went live in the deploys of their day.