Repository navigation
v3.10.0 — a copy is only true until somebody edits the original
Two agents went after v3.9.0 and the one path nothing had ever reviewed: what an operator writes, and everywhere it comes out.
One notice could spend a whole request's CPU
- The link rule's
[^\]]+rescans to the end of the body from every[. At the 4,000 characters the write path allows that is 13.97 ms — more than the 10 ms a Worker request is given — and the feed pays it twice, for the title and the body, uncached. - 1,000 → 0.86 ms, 4,000 → 13.97 ms, 16,000 → 164.11 ms before; 0.37 ms, 1.74 ms, 9.27 ms after.
- Nothing caps how many notices exist, and the page renders every open one.
A marker inside a URL wrote tags into the address
- Emphasis and code ran before links, so
[a](https://example.com/*x)producedhref="https://example.com/<em>x"— not an escape, since quotes are escaped unconditionally, but a corrupted address and an unmatched tag. - A link inside a code span was a working link.
- Code spans and links are held out of the rules that follow them, marked by a bare ampersand — the one character
esc()never emits, so an operator cannot type one. - Control characters are dropped rather than escaped; the HTML page was the only document still carrying them.
One language's resolved notices erased every other language's
- The resolved tail's cap was applied before the language filter rather than inside it. Thirteen resolved Turkish notices spent the whole window, and the one resolved English notice was unreachable from
/?lang=en,notices.json?lang=en, the English feed, andnotices.jsonwith no language at all.
The kind on an event row went stale
- v3.9.0 wrote
events.groupedat insert and read it as the monitor's current flag.monitors.groupedis the one column nabiz never writes: an operator edits it to move a service into a group, and every event written before that edit stayed in the window the service left. Measured: a moved member's 400 events filled the named window and the named service's history disappeared — the defect the two windows exist to prevent. - The same gap made the migration fragile. A database that got the column but not the fill — a process killed between them, or an operator running the first of three documented statements — was stuck that way forever, because the guard is the column.
- The hourly sweep sets the copy back to what
monitors.groupedsays, both directions. A half-applied migration repairs itself within an hour, and moving a monitor between groups is an edit and nothing more.
schema.sql could cost a database a table
- v3.9.0 put an index over the new column above the
noticestable. Applying the file to a v1.0.0 database fails there and skips every statement below it, so the database lost the table rather than gained the index. Every index now comes after every table, and the upgrade notes say to run the D1 statements before re-applying the file.
Fixed
- The round's deadline was published as the monitor's timeout: a host that answered 200 in 50 ms with a 60 s timeout it never came near was shown as "timed out". Only the monitor's own clock says that now.
oneLinestopped the C0 controls and let NEL, LINE SEPARATOR and PARAGRAPH SEPARATOR through — the forged alert line it exists to prevent, in three other characters.- A
severitythat was present but not a string was silently taken asinfoand answered 201; a client sending["outage"]during an outage published an info notice and was told it worked. postResolveaccepted1.5and1e308as ids.- Three sentences the code does not keep, including one written in the same commit that falsified it.
Ratchets that can be walked around are not ratchets
- An agent got round five of the three source-reading rules with their defects present. The memo rule guarded itself on a line the fix it was written for had changed, so it asserted nothing for a whole release — removing the warm entirely kept the suite green.
- All five are closed, and two new rules cover the two defects above that no rule could have caught: every index after every table, and the release proving the tag,
package.jsonand the version the code publishes agree before an image goes out. Until now the release gate was a two-line curl smoke test with nobun run checkin it.
Upgrading
- A container adds the index on start. On Cloudflare there is one statement in docs/UPGRADING.md, and it goes before any re-application of
schema.sql. - If you ran only part of the v3.9 block, nothing to do: the first sweep after this upgrade repairs it.