Skip to content

v3.12.0 — a sixth language, and the numbers checked

Choose a tag to compare

@productdevbook productdevbook released this 20 Aug 09:11
· 9 commits to main since this release

A sixth language from outside, and an audit of every number the page publishes.

Simplified Chinese

  • The page, the feed, notices.json and the alerts speak zh-CN, contributed by @Whbbit1999 in #5.
  • Three things a translation cannot see from inside its own file: the code is written into <html lang="…">, where zh_CN with an underscore is not a valid BCP 47 tag; percent() gave a comma and a space to everything that is not English or Turkish; and held() put the word before the number, so 之后 — a postposition — landed in front. The duration reads 已恢复 (2小时5分钟后) now.
  • ?lang=xx, ?lang=EN, ?lang=all and ?lang=en-US all answered English on a deployment configured for Turkish. langOf takes the language to fall back to, and every caller that has one passes it.

The uptime figure was summed over ninety-one days

  • day >= today − 90 returns today and the ninety before it; the strip draws ninety marks ending today. The headline figure therefore counted a day no bar shows: it moved 0.10% for a two-hour outage falling out of the window, up to 1.10% for a whole-day one, with nothing on the page changing. history.json published 91 entries under a window_days of 90.
  • Every window was open at the top and the sweep only deletes what is old. A container that boots with a clock a day fast wrote rows nothing could expel: a day dated tomorrow summed into today's uptime (99.65% where the ninety drawn days were 100%), a check timestamped tomorrow became the latency chip at 4000 ms, and updated_at — the field a machine watches to see whether the page is frozen — read the future.

An outage was reported shorter than it was

  • since was written when the threshold was crossed, not when the failures began, so every recovery message was fail_threshold - 1 rounds short: 60 seconds at the shipped default, and held() floors to whole minutes, so a two-minute outage was announced as "1 min".

One member's bad day is not the group's

  • medianDays took the lower of two middles, so a group of two published the worse member's row — counts, timings and all — as the group's history, while the same row's state line said "partly up" because isDown refuses to call two-member trouble an outage. The history follows the state rule now: never worse than the second-worst. Two bad members make a bad day; one never does.

The waveform was a queue of readings, not a day

  • Points were placed by their index, and the store returned only the hours that had a successful probe — so a nine-hour hole, a probe loop dead all afternoon, drew as one step between adjacent pixels under a title reading "last day". There is a slot per hour now and the line breaks across the empty ones. It also returned 25 buckets for a 24-hour window.
  • percent() floored pct * 100, which in binary is 1839.9999999999998 for 18.4, so 23 of 125 probes published as 18.39%.

The page on a phone

  • v3.11.0's white-space: nowrap on an event's time was right for the two places a timestamp sits alone and wrong for the event row: the time ran past a panel that hides its overflow. At 320px in German, six of six rows clipped, 116 pixels of a 122-pixel timestamp — worse than the wrapping it replaced.
  • The same release wrapped .svc header to give the name room, which moved the uptime figure and nothing else; the pill and the latency sit inside .who and never left the name's line. Five of seven cards gained a row without gaining a character. Now the name takes the first line and as much of a second as it needs: "Documentation and developer portal (europe-west-1)" reads in full at 320px, where it showed 59 pixels.
  • A bar grows by a share of its height on hover, so the 3px no-data bar moved half a pixel; it grows by three times instead. The day gap steps 3px, 2px, 1px rather than falling off a cliff at 601px.

Ratchets, third pass

  • An agent walked around fourteen rules with bun run check at zero. The schema-order rule had already survived lower case and CREATE UNIQUE INDEX; this time an index rode the ); closing a table. The release gate fell to continue-on-error: true, then to deleting both steps and leaving their words in a comment. The theme rule could not see a colour that was not a token. The public-repository rule read hostnames only after http(s)://, missed a Telegram token stored without its bot prefix, and skipped .github/ — where a database id sat happily.
  • All closed, each verified by replaying the walk-around.

Upgrading

  • A container adds the column on start. On Cloudflare there is one ALTER in docs/UPGRADING.md.
  • A recovery message for an outage that began before this upgrade counts from what the old row knew, which is what today's code already assumed.