Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a0a212e
Stop database contention from blanking the board, and fix the legend
Londopy Aug 4, 2026
d40966c
Put seeded responders where they can be seen
Londopy Aug 4, 2026
a71b99f
Say on the report page who has stopped answering
Londopy Aug 4, 2026
166ef47
Draw responders the way the legend says, and give the map a way home
Londopy Aug 4, 2026
bb38dd2
Read Voluntweeters and record what it does not cover
Londopy Aug 4, 2026
a635e2b
Read Kendra and Wachtendorf and restate the claim it survives
Londopy Aug 4, 2026
b0f7aed
Outline the ISCRAM work-in-progress paper
Londopy Aug 4, 2026
5796aef
Draft the design section
Londopy Aug 4, 2026
ac7cc41
Record what Liu's abstract settles and what stays open
Londopy Aug 4, 2026
bd1cda3
Mine Liu's citation list for the papers that actually matter
Londopy Aug 4, 2026
e557cd9
Keep Liu's bibliography, note that the body is still unread
Londopy Aug 4, 2026
5820cea
Draft what we learned and the limitations
Londopy Aug 4, 2026
787d892
Take the worker count from the host instead of overriding it
Londopy Aug 4, 2026
67dbae9
Note why the demo stopped booting
Londopy Aug 4, 2026
e878e23
Draft the introduction and future work, and plan preprint before review
Londopy Aug 4, 2026
f1c495c
Find the open copies and correct which Harvey paper we actually need
Londopy Aug 4, 2026
44aed81
Write the Harvey paragraph from a source
Londopy Aug 4, 2026
edd5b3f
Put the argument against us in the limitations
Londopy Aug 4, 2026
cfc5389
Mark the introduction sourced
Londopy Aug 4, 2026
e04d733
Read the doctrine the argument was resting on
Londopy Aug 4, 2026
e3d7d7d
Draft the related work
Londopy Aug 4, 2026
7618044
Read the 1957 original instead of citing it secondhand
Londopy Aug 4, 2026
04811bd
Draft the abstract and title
Londopy Aug 4, 2026
8af830e
Assemble the sections into one paper
Londopy Aug 4, 2026
8c66554
Cite the paper we read, drop figures we cannot check, draft the discl…
Londopy Aug 4, 2026
55b3836
Leave the disclosure to the authors
Londopy Aug 4, 2026
c0f0003
track paper LaTeX source and wire up citations
Londopy Aug 4, 2026
be44f8c
add author affiliations and ORCID to title block
Londopy Aug 4, 2026
99d8269
drop authblk and remove placeholder affiliation
Londopy Aug 4, 2026
3690aeb
add second author email to title block
Londopy Aug 4, 2026
7047352
keep the paper out of the repository line counts
Londopy Aug 5, 2026
0f02a4e
add a scaled clock so the escalation can be filmed
Londopy Aug 5, 2026
fe6a701
document the scaled clock across the docs and changelog
Londopy Aug 5, 2026
d0fd3aa
move the demo paragraph out of future work
Londopy Aug 5, 2026
5f42764
fix the countdown vanishing on repaint and the board contrast
Londopy Aug 5, 2026
58a6c8a
audit every stylesheet for contrast and both board renderers for drift
Londopy Aug 5, 2026
963039e
catch the docs up with the accessibility review
Londopy Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ env/

# Database
*.db
# WAL leaves two sidecar files beside the database. They are as much a local
# artefact as the .db itself, and a committed -wal is a committed transaction
# log from somebody else's machine.
*.db-wal
*.db-shm
*.sqlite
*.sqlite3

Expand Down Expand Up @@ -48,3 +53,6 @@ site/.astro/
# Committing them would give every page two copies, and someone would edit
# the wrong one.
site/src/pages/*.md

# Overleaf upload bundle is built from paper/ -- see paper/README.md
diresq-overleaf.zip
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ Disaster response tracker. Logs the volunteers going in, not just where the disa

### Added

- The clock can be scaled, so the thing this project is about can be watched instead of described. DiresQ's mechanism is the absence of an event over time — a deadline passes, nobody hears from a responder, and fifteen minutes later the server files a report about them — which is correct and completely unwatchable. `DIRESQ_DEMO_SPEED` multiplies the rate incident time passes: at 60, a responder goes overdue five seconds after the page loads and the report about them arrives fifteen seconds after that. Nothing about the mechanism is faked for the camera. There is one `now()` and every deadline, comparison and query downstream is the production code, unchanged; only the rate time enters the system is scaled. Login lockout and the ICS-214 export filename deliberately stay on the real clock, the first because scaling a security control on a public instance is not a demo feature and the second because it names a file on somebody's disk. A scaled clock forces the demo banner on and makes it state the multiplier, for the same reason the board shows when the sweep last ran: a page showing accelerated time has to say so, or the honest version of this is indistinguishable from a faked one.
- The accountability board shows time remaining, not only time elapsed. Every row already said how long since we last heard from somebody, which states the past and leaves the future to be worked out. It now also says *due in 5 min*, counting down, and *20 min past due* once it isn't. The number is in the `/api/responders` payload as `due_in_seconds`, negative once the deadline has gone.
- A seeded responder whose deadline expires while you are looking at it. Everybody else on the demo board is in a state that has already settled — Sam is red, the Mayde Creek four are overstaffed, the rest have time in hand. `n.farrow` is the only one whose state changes on screen, because a transition needs a before, and the first attempt gave them the *longest* deadline on the board, so every other responder went red first and there was nothing to point a camera at. A test now asserts they lead the queue by at least three minutes, so a later change to the seed cannot quietly take the shot away again.
- `docs/filming.md`: the arithmetic that turns a speed into a shot (red at 300/S seconds, the auto-filed report at 1200/S), why speeds above about 120 look broken rather than fast — the board refreshes every three seconds, so the countdown starts jumping by more than it counts down — and a shot list that opens cold on a red board rather than on anybody introducing themselves.

- Two buttons on the map for when you have lost the incidents. *Fit all* frames every report currently shown — including after the coverage filter has hidden some, so it frames what is left rather than what it just hid. *Next report* walks through them one at a time and opens each. Both say where they went to a screen reader, because moving a map is silent.
- A `CONTRIBUTING.md` and a `CODE_OF_CONDUCT.md`. The contributing guide is specific rather than generic: a fix arrives with a test that fails without it, numbers in prose have to be true because a test reads them, a weakened guarantee gets a paragraph in `limits.md`, and nothing that stops being true when it is written may be cached. The code of conduct is the Contributor Covenant with two additions — one rule about not putting real emergency information into a demo that cannot summon help, and an honest note that two students are not a moderation team, with a pointer to GitHub's own report-abuse flow for anything urgent.
- The board now shows when the silence check last ran — "checked 2s ago" beside the live indicator, turning amber if it has not run for five minutes. The check that files a report about somebody who has gone quiet has no scheduler: it runs whenever anybody reads the board, so it cannot be a timer that dies without anyone noticing. But that was a claim in a comment, and this project does not ask anyone to take a claim about an alarm on trust. On a board somebody is watching the number always reads a few seconds, because the watching is what runs it — which is the point. You can watch it move instead of believing it.
- `app.py` opens with an index of what is in it: fifteen sections in running order, each one a banner comment you can search for. It is one file on purpose, and the cost of that is knowing where anything is. There are no line numbers, because they would be wrong by the next commit, and a test checks the index and the file still agree — including the order.
Expand All @@ -14,10 +20,28 @@ Disaster response tracker. Logs the volunteers going in, not just where the disa

### Changed

- `docs/accessibility.md`, `docs/limits.md` and `docs/decisions.md` caught up with the demo clock. The accessibility page records the fourth pass and the three things it found, and its enforcement table now lists what the new tests actually check rather than what the old ones did — including the detail that the full-stylesheet contrast audit got its light/dark classification wrong on the first attempt and was caught by its own canary. `limits.md` records that screen reader users do not get the countdown at all, why the alternative was worse, and that the honest fix is not written. `decisions.md` records why time is injectable rather than the constants being shortened in demo mode, and what stays on the real clock.


- The tests that read the project's own files stopped walking into `node_modules` before discarding it. They were the slowest thing in the suite and are now roughly thirty times faster.

### Fixed

- Six stylesheets were setting real text in `#6c7086` or `#45475a`, which are 1.4:1 to 1.9:1 against the surfaces they sit on where WCAG asks for 4.5:1 — the disclaimer's footer, the legal links under the login, signup and homepage forms, the offline page's "as of" stamp and footer, the triage footnote, and the stood-down vote and capability tags on a report. The test that was supposed to prevent this checked ten hand-listed colour pairs, so a colour used in a file nobody had thought to add to the list was never looked at. It now reads every `color:` declaration in every stylesheet, resolves `var()` against each file's own palette, and checks it against the backgrounds it can actually sit on.


- The countdown on the accountability board survived exactly one render. It was added to the server-rendered template and not to the JavaScript that replaces the list every three seconds, so it appeared on load and was wiped by the first poll — invisible in the test suite, which reads the template, and invisible by hand unless you happened to watch the same row for three seconds. A test now asserts both renderers draw it. The board's coordinates and its "not assigned" / "no position" / "no contact yet" states were using `--overlay` on the row background, which is 1.92:1 against WCAG's 4.5:1. That grey has been banned from `a11y.css` by a test since it was caught on capability tags; `board.css` was never covered by it and now is.


- The hosted demo stopped booting. The boot script asked for two gunicorn workers on a 512 MB instance, and the classifier trains when the app is imported, so each worker carried its own copy. Render prints the worker count it sized the box for — one — in its own deploy log, and passing `--workers 2` silently overrode it. The container was killed four seconds after starting, and the platform then spent seventeen minutes health-checking a process that was already dead, which is why the failure reported itself as a health check that never passed rather than as a boot that never survived. The count now comes from the host.
- Responders were drawn on the map in a way the legend no longer described. The legend key had been changed to a hollow ring — colour was already saying whether anyone is coming to a place, so it had nothing left to say about a person — but the map was still drawing them as solid circles in those same three colours. So the symbol people were told to look for did not exist, and the ones that did exist looked like reports. Fixing a label without fixing the thing it labels leaves a page telling two lies instead of one.
- The board, the map and the feed could return an error page under load. All three run the silence check before answering, the check writes to the database, and SQLite lets one writer lock out every reader — so with a few people watching a board that refreshes every three seconds, a write could wait past its timeout and fail the whole response. The pages that exist to be watched during an emergency were the ones that broke when watched. Three changes: the database now uses a journal mode where readers and the writer stop blocking each other, the check runs at most once every thirty seconds instead of once per visitor per refresh, and a failed check is caught rather than allowed to become an error page. It deliberately does not record itself as having run when it fails, because a board showing green while nothing is checking is the worst outcome available.
- A report could say somebody was on scene while the board had them forty-five minutes overdue, and the report page gave no sign of it. Status is what a responder last told us; whether they are still answering is a different fact, and only one of the two pages knew it. Anybody opening a report to decide whether the address needed more help was counting a person who had gone silent as help. The page now says how many have stopped answering, marks each of them, and says plainly not to count them. Somebody who has cleared is not chased, because going home is not going quiet.
- On a phone, the only way to file a report was to open a menu labelled "Filter". The button lived in the sidebar, which slides off-screen below 768 pixels, so the one thing this app exists to do was behind the one control nobody would press to do it. There is now a Create Report button in the page itself on small screens, and exactly one of the two is ever present so a screen reader never hears it twice.
- Seeded responders were on the map and could not be seen. They were placed within ninety metres of the report they had joined — close enough that the circle marking a person sat underneath the teardrop marking the place, and Leaflet draws places above people. Nothing was missing from the data, which is exactly why nothing looked wrong with it. They now stand off by about two hundred metres, so the thing this project is an argument about — several people converging on one address — is visible rather than inferred.
- The demo moved every time the server restarted. Responder positions were derived from Python's built-in string hashing, which is deliberately salted differently for each process, so a seed built on the promise that every visitor arrives at the same incident produced a different incident on every boot. It now uses a checksum that gives the same answer on every machine and every run.
- The map legend used the same red for *nobody going* and for *responder*, so two of its four keys said different things in the same colour. Colour was already carrying meaning — red, blue and green say whether anyone is coming — which left nothing for it to say about a person. The legend now uses shape the way the map already does: reports are teardrops, responders are a hollow ring. Colour means one thing on each.
- The map stopped telling the difference between having no signal and the server returning an error, so a failure looked like being offline. It now checks the response before believing it, and the warning appears above the map rather than underneath the statistics, where a phone screen never reached it.
- The stamp that records when the silence check ran could take down the page it is displayed on. It runs before every read of the board, which polls every three seconds, so something that had been read-only started writing on every request — and a write that fails inside a before-request hook returns an error page instead of a board. It now fails quietly: the timestamp goes stale and the board reports that in amber, which is true, because a check we could not record is not a check we can claim.

## [1.0.2] - 2026-08-03
Expand Down
Loading
Loading