2026-08-18 - a tower of giraffes
·
117 commits
to main
since this release
What's Changed
- Make admin routes their own source of truth by @stefan-burke in #1882
- Stop catalog imports loading unrelated page copy by @stefan-burke in #1883
- Add complete local SQLite snapshots by @stefan-burke in #1884
- Keep catalog fields in one place by @stefan-burke in #1885
- Lower the code complexity limit to 13 by @stefan-burke in #1887
- Restore database backups safely and quickly from the console by @stefan-burke in #1886
- Avoid fragile maintenance batch transactions by @stefan-burke in #1889
- Keep maintenance task sync on the primary by @stefan-burke in #1890
- Lower production code complexity limit to 12 by @stefan-burke in #1891
- Retry temporary BunnyDB 421 read failures by @stefan-burke in #1892
- Move refund and SMS tests beside their features by @stefan-burke in #1893
- Give maintenance its own database budget by @stefan-burke in #1894
- Handle Square webhook identifiers safely by @stefan-burke in #1895
- Share string entry filtering by @stefan-burke in #1896
- Keep cutoff timestamps consistent by @stefan-burke in #1897
- Make mutation checks faster and stricter by @stefan-burke in #1898
- Add direct tests for payment pricing by @stefan-burke in #1900
- Document the Nix development workflow by @stefan-burke in #1902
- Colocate payment and webhook integration tests by @stefan-burke in #1899
- Move bulk refund result messages into locale catalog by @stefan-burke in #1901
- Add Uptime Kuma checks for built-site maintenance by @stefan-burke in #1888
- Split the Uptime Kuma modules into one concept per file by @stefan-burke in #1906
- Load heavy modules only when needed by @stefan-burke in #1903
- Add social media sized screenshot variants by @stefan-burke in #1907
- fix: CodeRabbit auto-fixes for PR #1907 by @coderabbitai[bot] in #1908
- Add stable Stripe and Square refund idempotency keys by @stefan-burke in #1912
- Clean the equivalent-mutant registry with the static audit by @stefan-burke in #1910
- Harden payment, SMS webhook, and order gallery tests by @stefan-burke in #1909
- Test folded and ordinary booking directly by @stefan-burke in #1913
- Stop grouped suites leaking CAN_BUILD_SITES across the env overlay by @stefan-burke in #1914
- Add executable payment acceptance stories by @stefan-burke in #1915
- Accept only confirmed Square refund outcomes by @stefan-burke in #1911
- Record folded-booking line 381 dayCount equivalent by @stefan-burke in #1916
- Add regression tests for DB env scope lifecycle and cached guide pin by @stefan-burke in #1919
- Move no-quantity ticket journeys to Cucumber by @stefan-burke in #1920
- Build booking rows consistently for paid and free orders by @stefan-burke in #1904
- Move servicing event journeys to Cucumber by @stefan-burke in #1921
- Document licensing, security, and SumUp; improve local precommit runs by @stefan-burke in #1918
- Add direct Turso database migration by @stefan-burke in #1923
- Publish acceptance-tested screenshots for the website by @stefan-burke in #1924
- Use one shared system for all tables by @stefan-burke in #1922
- Test volunteer sign-ups and payment choices as user journeys by @stefan-burke in #1925
- Stop test databases slowing down after a transaction by @stefan-burke in #1928
- Write the booking, backup and attendee editing journeys as readable stories by @stefan-burke in #1927
- Read each listing's links once per page, and run CI checks beside the tests by @stefan-burke in #1930
- Copy plain columns straight across when reading a row by @stefan-burke in #1932
- Write the refund and money-handling journeys as readable stories by @stefan-burke in #1931
- Hide payment providers your currency cannot use by @stefan-burke in #1933
- Split the test files that cover more than one thing by @stefan-burke in #1929
- Write the multi-day stay journeys as readable stories by @stefan-burke in #1934
- Point every copyable example at a file that exists by @stefan-burke in #1937
- Write the mixed-order journeys as readable stories by @stefan-burke in #1938
- Let the dev shell's throwaway defaults be overridden by @stefan-burke in #1936
- Trim the comments down to what the code does not already say by @stefan-burke in #1939
- Stop rebuilding the browser assets before every test run by @stefan-burke in #1935
- Write the duplicate-merge and bulk-money journeys as stories, and write down how to migrate one by @stefan-burke in #1941
- Fix two mistakes in the asset cache: wrong docs, and a test that watched the clock by @stefan-burke in #1942
- Write the income, deposit and correction journeys as readable stories by @stefan-burke in #1943
- Move sites off Bunny databases from one menu by @stefan-burke in #1940
- Write the by-hand booking and attendee download journeys as stories by @stefan-burke in #1947
- Stop the test harness waiting on stripe-mock, and speed up owner-key encryption by @stefan-burke in #1945
- Tighten the tests behind the database host and backup names by @stefan-burke in #1946
- Start mutation-checking the scripts/ folder by @stefan-burke in #1944
- Write the listing-change and race journeys as stories by @stefan-burke in #1948
- Stop tests comparing byte arrays one number at a time by @stefan-burke in #1949
- Write booking through the API as a story by @stefan-burke in #1950
- Fully test the isolated mutation runner by @stefan-burke in #1951
- Make the order gallery test say what its waiting time means by @stefan-burke in #1953
- Write add-ons sold on their own as a story by @stefan-burke in #1952
- Move the phone-index tests next to the code they test by @stefan-burke in #1955
- Fully test the isolated mutation run state by @stefan-burke in #1954
- Write the record kept about someone as a story by @stefan-burke in #1956
- Fully test the stripe-mock starter by @stefan-burke in #1960
- Make the email variable descriptions translatable by @stefan-burke in #1958
- Write checking people in at the door as a story by @stefan-burke in #1959
- Fully test the spec runner by @stefan-burke in #1963
- Fix organisations on Turso by @stefan-burke in #1961
- Write booking from a code on the door as a story by @stefan-burke in #1964
- Split the database migration runtime into smaller files by @stefan-burke in #1965
- Capture door check-in evidence from its Cucumber case by @stefan-burke in #1967
- Tidy two repetitive test files by @stefan-burke in #1969
- Test how stripe-mock is fetched and installed, and fix two faults it uncovered by @stefan-burke in #1966
- Stop one test taking another's port and reading it as success by @stefan-burke in #1970
- Clear away mutation run copies, and give every lock one shared mechanism by @stefan-burke in #1957
- Say why a listing does not fit its group by @stefan-burke in #1971
- Make the admin API example match the real responses by @stefan-burke in #1974
- Tidy the file-size note, the last stray test, and stale mutant lines by @stefan-burke in #1972
- Run the equivalent-mutant audit in its own copy of the checkout by @stefan-burke in #1976
- Bundles and editor permissions become stories, and the story helpers get tidied by @stefan-burke in #1968
- Fix the API documentation examples that could never have worked by @stefan-burke in #1975
- Ask the database for things the same way everywhere by @stefan-burke in #1977
- Two TODOs: a mutation command that deleted folders it did not make, and a 944-line test file by @stefan-burke in #1980
- Let notes be about any record, not only an attendee by @stefan-burke in #1978
- Say where each evidence story was authored by @stefan-burke in #1979
- Break three oversized test files into small, focused ones by @stefan-burke in #1981
- Two more stories: keys handed to other systems, and the site's own pages by @stefan-burke in #1983
- Put the check-in helper's comment back on the helper by @stefan-burke in #1984
- Prove what the balance payment link tells a customer by @stefan-burke in #1985
- A story for the visitor who writes to the owner by @stefan-burke in #1986
- Let a read say what it wants instead of spelling out SQL by @stefan-burke in #1982
- Capture the contact record and the bundle booking page by @stefan-burke in #1989
- Stop splitting a test file into a folder making mutation runs slower by @stefan-burke in #1987
- Say what a read wants, instead of writing out its SQL each time by @stefan-burke in #1991
- Check the whole booking a payment sends back, not only its lines by @stefan-burke in #1990
- Test what keeps encrypted files readable by @stefan-burke in #1992
- A story for setting a new site up by @stefan-burke in #1988
- Leave three more pages behind for the site to photograph by @stefan-burke in #1994
- Say why the owner has a person's name, without naming the old one by @stefan-burke in #1998
- Test the attendee page, attendees list, listing loaders and store-and-refund by @stefan-burke in #1993
- Leave three more pages behind for the site to photograph by @stefan-burke in #2001
- Check a turned-away request goes to the login page, not just "not OK" by @stefan-burke in #2000
- Stop duplicating a listing failing with an unexplained error by @stefan-burke in #2002
- Leave two more pages behind for the site to photograph by @stefan-burke in #2003
- Write the stay-length pages, mixed-length stays, and stay check-in as stories by @stefan-burke in #1999
- Test what the news pages promise, and refuse a post date that isn't real by @stefan-burke in #2004
- Take a real migration lock as soon as the settings table exists by @stefan-burke in #2005
- Let a new row report its own id, instead of asking the database driver by @stefan-burke in #2009
- Leave five more pages behind for the site to photograph by @stefan-burke in #2008
- Tell the example-data journey as a story, and harden what review found by @stefan-burke in #2006
- Add a dev task that restarts on source changes by @stefan-burke in #2010
- Add the tables one payment record lives in by @stefan-burke in #2007
- Give stories one typed memory, and one place to put things back by @stefan-burke in #2012
- One way to read a table's rows by @stefan-burke in #2015
- Read through the table wherever the table can answer by @stefan-burke in #2016
- Tie each screenshot's page to the capture it is for by @stefan-burke in #2013
- Prove the tests catch real mistakes, and tell the admin stories in plain English by @stefan-burke in #2011
- Give notes, images, and page items one way to name a record by @stefan-burke in #2014
- Fix Bunny deploy action supply chain risk by @stefan-burke in #1996
- Prevent duplicate first-run setup by @stefan-burke in #1997
- Tell holidays, discount codes, and the news as Cucumber stories by @stefan-burke in #2017
- Prove a guessed promo code tells the customer nothing by @stefan-burke in #2018
- [codex] Fix agent check-in PII access by @stefan-burke in #1995
- Follow Stripe's listing cursor when fetching webhook endpoints by @stefan-burke in #2024
- Tell the privacy and list-narrowing journeys as Cucumber stories by @stefan-burke in #2023
- Keep a fresh lockout when cleaning up an expired one by @stefan-burke in #2026
- Remove leftovers by @stefan-burke in #2027
- Cap the session cache so junk cookies cannot grow it forever by @stefan-burke in #2028
- Route repeated admin wiring and duplicated helpers through one shared mechanism each by @stefan-burke in #2029
- Sort the stories into buckets that say what they hold, tell the booking states as a story, and stop a test doing what no visitor could by @stefan-burke in #2025
- Fix backup folder naming and freshness edge cases; strengthen the admin debug tests by @stefan-burke in #2031
- Tell the story of writing to the people who booked by @stefan-burke in #2034
- Fold the settings forms and delete pages onto their one shared builder each by @stefan-burke in #2033
- Only strip the UUID prefix from Bunny lite hostnames, and keep the freshness helper private by @stefan-burke in #2032
- Look things up in batches, so a big booking does not run out of requests by @stefan-burke in #2036
- One shared shape for "you can't do that, and here's why" by @stefan-burke in #2035
- Keep existing payments working when new sales are off by @stefan-burke in #2020
- Count rate-limit attempts in one atomic statement per limiter by @stefan-burke in #2040
- Finish a booking in the same few database calls, however many things were booked by @stefan-burke in #2041
- Read a list row's own controls, not the whole page's by @stefan-burke in #2039
- Bind repeated SQL values once with numbered parameters by @stefan-burke in #2043
- Test the gaps the batched-lookup change left behind by @stefan-burke in #2038
- One shared "claim that can go stale" for the install lock and mutation runs by @stefan-burke in #2042
- Record equivalent mutants by what they sit inside, and catch drift on every commit by @stefan-burke in #2037
- Stop the upload test racing a real server, and stop it taking the suite down by @stefan-burke in #2045
- Work out what is left for every booking length from one reading by @stefan-burke in #2044
- Capture evidence for editor, restore, and CSV stories by @stefan-burke in #2047
- Finish paid bookings in a fixed number of database calls by @stefan-burke in #2048
- Show the site menu on booking pages, hiding it only in iframe mode by @stefan-burke in #2051
- Make interrupted mutation copy-back tests deterministic by @stefan-burke in #2053
- Run mutation static checks in parallel by @stefan-burke in #2052
- Export editable screenshot layers by @stefan-burke in #2049
- Keep registration webhooks direct and bounded by @stefan-burke in #2050
- Fold the real-calendar-day check into one helper by @chobble-opencode-vm[bot] in #2054
- Fold the download-response builders into one helper by @chobble-opencode-vm[bot] in #2055
- Agent-operating docs and payment-aggregate integration plan by @stefan-burke in #2030
- Make group, package, and parent checks atomic by @stefan-burke in #2046
- Condense the payment plan into standalone milestones by @stefan-burke in #2057
- Close the plan review round that landed after the merge by @stefan-burke in #2058
- SumUp callbacks go behind the strict observation boundary (M3) by @stefan-burke in #2060
- Delete the sumupApi and squareApi alias wrapper exports by @stefan-burke in #2061
- Assert the SumUp callback contract in the sandbox e2e by @stefan-burke in #2062
- Recheck listing relationships inside transactions by @stefan-burke in #2059
- M4 behavior contract: one diagnosis for settled money (PR4_PLAN.md) by @stefan-burke in #2063
- Aim a bulk email at one day of a listing booked by the day by @stefan-burke in #2067
- Migrate a stale database without stalling on the lock timeout by @stefan-burke in #2066
- Leave the day's compose page as evidence by @stefan-burke in #2068
- Leave the free listing's own page as evidence by @stefan-burke in #2069
- Leave a costed hold's page as evidence by @stefan-burke in #2070
- Style the embed cart so a strict host-page CSP can't block it by @stefan-burke in #2071
- Drive lazy prefix routing from declarative maps by @stefan-burke in #2072
- Stop capturing specification evidence on every pull request by @stefan-burke in #2073
- Migrate story: copy a group of listings by @chobble-opencode-vm[bot] in #2076
- Migrate story: take a group off sale by @chobble-opencode-vm[bot] in #2077
- Migrate stories: choosing a bulk action, bringing a group back on sale, and asking to be left alone by @stefan-burke in #2082
- Hold comments to a size, and start bringing them down by @stefan-burke in #2081
- Make refunds safe to retry, recover, and review by @stefan-burke in #2065
- Payment machines as checked tables, and refunds that finish after a crash by @stefan-burke in #2079
- Cut the attendee select comments in half by @stefan-burke in #2083
- Map the seams between the payment machines by @stefan-burke in #2084
- Point the plan at the merged seam work and make the method a rule by @stefan-burke in #2086
- Trim db/client.ts comments, fix five that pointed at nothing, and check for it from now on by @stefan-burke in #2085
- Let ordinary refunds fit the request budget by @stefan-burke in #2087
- Read a listing's children and parents in one go by @stefan-burke in #2088
- Read a session and its user in one go by @stefan-burke in #2089
- Cover the JSON API's role gate by @stefan-burke in #2091
- Read the public nav's three small tables in one go by @stefan-burke in #2090
- Stop the two-charge refund test depending on which send lands first by @stefan-burke in #2092
- Answer canRefund from the lines the page already loaded by @stefan-burke in #2093
- Read the ledger's pre-write checks in one round trip by @stefan-burke in #2094
- Close the ledger's mutation gaps, and stop the timeout hiding them by @stefan-burke in #2095
- Write down what the closed payment rewrite taught us by @stefan-burke in #2096
- Stop the mutation runner judging a mutant by a clock by @stefan-burke in #2097
- Delete the row before the file, and block group moves that strand an add-on by @stefan-burke in #2099
- Show backup-listing failures and stop the create button crashing on big databases by @stefan-burke in #2101
- One shared way to filter and sort every attendee list by @stefan-burke in #2098
- Let mutation runs score dates.ts by making every mutant terminate by @stefan-burke in #2100
- Close the backup mutation gate's thirteen survivors by @stefan-burke in #2102
- Give the demo data and the listing form their own tests, and stop loops that could run forever by @stefan-burke in #2103
Full Changelog: v2026-07-22-105033...v2026-08-18-095849