Skip to content

Demo mode, the paper, and an accessibility pass - #2

Merged
Londopy merged 37 commits into
Skythe7:mainfrom
Londopy:main
Aug 5, 2026
Merged

Demo mode, the paper, and an accessibility pass#2
Londopy merged 37 commits into
Skythe7:mainfrom
Londopy:main

Conversation

@Londopy

@Londopy Londopy commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Backend work since the hackathon: a demo you can watch, and the paper

37 commits, 49 files, +5,280/−104. It is a lot at once, and it splits cleanly
into four things. Read whichever you care about — they don't depend on each
other.

Nothing here touches the frontend templates you own except board.html,
which gained one span, and a <br> in the demo banner on eight pages. Details
in section 3.


1. The fix that matters most: the mechanism can now be watched

Commits: 0f02a4e, fe6a701, 5f42764

The thing DiresQ is about is an absence — a deadline passes, nobody hears from
a responder, and fifteen minutes later the server files a report about them.
It is correct and it is impossible to show anybody. You cannot demo the
non-occurrence of an event in ninety seconds.

That is, I think, most of why we lost Katy. A judge with two minutes could not
form the mental model, so nothing else we built got looked at.

So the clock is injectable now:

export DIRESQ_DEMO_SPEED=60
flask --app app init-db && flask --app app seed && flask --app app run

Open /board. A responder goes overdue five seconds after the page loads, and
at twenty seconds "No contact from n.farrow for 20 minutes" appears in the
feed on its own. Nobody clicks anything.

Nothing is staged. There is one now() function and every deadline,
comparison and query downstream is the production code untouched — only the
rate at which time enters the system changes. 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.

A scaled clock forces the demo banner on and makes it state the multiplier,
which is the same rule the board already follows about showing when the sweep
last ran.

docs/filming.md has the arithmetic and a shot list. Never set this
anywhere real
— it is the one env var whose misconfiguration is invisible.

2. The paper

Commits: bb38dd2 through c0f0003, plus 7047352

There is an eleven-page preprint in paper/, LaTeX, builds clean with
pdfLaTeX + BibTeX. Ten references, all of them read or explicitly marked as
abstract-only in the text.

The short version of what the reading found: our original claim — nobody
tracks the people who go in
— is false, and a reviewer would have known.
Convergence has been documented since Fritz & Mathewson in 1957. The field's
answer is credentialing, credentialing presupposes an authority who has
already arrived, and FEMA's own guidance answers the 2am boat owner by
saying they should have affiliated months earlier. The interval before an
authority exists is the actual gap, and that is what the paper is about.

The limitations section says plainly that DiresQ has no users, no deployment
and no evaluation. It also includes the strongest argument against our
design, which comes from the people we claim to serve — the Harvey volunteers
interviewed by Smith et al. wanted more coordination, not less.

Three things still open, and one is yours as much as mine:

  • Three sources are cited from their abstracts only (Liu 2014, Auferbauer &
    Tellioğlu 2017, Kankanamge et al. 2019). Noted in the text where they appear.
  • SocArXiv's AI policy means the prose has to be rewritten in our own words
    before it can be posted there. The research, argument and design are ours;
    the sentences are not yet.
  • You have not read it. Author order isn't decided either. Neither should
    be settled by me merging a PR.

paper/README.md has the full state.

3. Accessibility and a bug that would have broken the video

Commits: 5f42764, 58a6c8a, 963039e

A review of the countdown found three things, one serious:

  • The countdown was drawn once and erased three seconds later. I added it
    to templates/board.html and not to board.js, which replaces the list on
    every poll. It rendered on load, and the first poll wiped it. No test saw it
    because the tests read the template. The demo was broken in exactly the
    configuration we would have filmed it in.
  • A number that changes on every repaint was sitting inside the
    aria-live="polite" region, which would bury the announcement that matters
    (the badge going OVERDUE). It is aria-hidden now, and the trade is written
    down in limits.md rather than only in a commit message.
  • #45475a and #6c7086 were being used for real text at 1.4:1 to 1.9:1
    across seven stylesheets — the board's coordinates and "no position" states,
    the disclaimer footer, the legal links under the login, signup and homepage
    forms, the offline timestamp, the triage footnote.

The contrast test that was supposed to prevent that last one checked ten
hand-listed colour pairs and never read a stylesheet. It now reads every
color: declaration in every stylesheet and resolves var() against each
file's palette. There is also a test asserting board.html and board.js
draw the same fields, and another asserting every fragment rowHtml builds
actually reaches the output — because field parity alone stays green if the
interpolation is deleted and the local left behind.

The audit count in the README moved from nineteen to twenty-two.

4. Smaller things

  • 787d892the Render outage. We hardcoded --workers 2 on a
    512 MB instance that announces WEB_CONCURRENCY=1. The classifier trains at
    import, so two workers meant two copies, and the container was killed four
    seconds after boot. It now takes the host's number.
  • 166ef47, d40966c, a71b99f — responders drawn the way the legend says
    they are, seeded somewhere visible, and the report page says who has stopped
    answering.
  • a0a212e — WAL mode. The board, map and feed all wrote on read, and SQLite's
    default journal let one writer lock out every reader. The three pages whose
    whole purpose is to be watched continuously were the three that fell over
    when watched continuously.

Checks

745 tests               passing
ruff --select=E9,F      clean
patchnotes --strict     0 errors, 0 warnings
node --check            every shipped script parses

The doc-freshness suite caught me three separate times while doing this —
twice on test counts I had measured with a sloppy grep, once on the README
line total after the paper landed in the repo. It works.

After this merges

The launchers in scripts/ hardcode Skythe7/DiresQ, which is correct here
and would have been broken had I tagged a release on my fork. So the release
should be cut from this repo, not mine:

patchnotes CHANGELOG.md bump 1.1.0
git tag v1.1.0 && git push origin v1.1.0

1.1.0 rather than 1.0.3 — the clock is a feature, and there are 24 entries
under [Unreleased]. If the Zenodo integration is on, publishing that release
mints a DOI, which gives the paper a citable artifact to point at instead of
just saying "open-source".

Londopy added 30 commits August 3, 2026 18:04
@Londopy
Londopy merged commit 100f833 into Skythe7:main Aug 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant