Fix what a retroactive review found in what the site publishes - #53
Merged
Merged
Conversation
…pages build dropped outages restored before collection began from each county's list, as the county page, shard and CSV require, but area_index and the search index were built from the unfiltered list. areas.html, the area pages, the county page's area card and search.js counted 14 outages the county page did not list, and an area whose only event was one of them got a page and a sitemap entry. One helper now applies the rule everywhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
county_csv wrote ESB's free-text location, the Census town and the planned reason as-is, so a cell opening with =, +, -, @, tab or carriage return ran as a formula in the spreadsheet a reader opened c/<slug>.csv in. Those cells now get the usual leading apostrophe. No location in the corpus starts with one today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
--now was parsed with .replace(tzinfo=UTC), which relabels a timestamp carrying an offset rather than converting it: 10:00+01:00 built as 10:00 UTC, an hour late, enough to move a day cell or a month boundary. It is now converted, and a bare timestamp is still read as UTC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
…rowing The county row's onclick put the name inside a JS string with esc(), which the HTML parser undoes before the script runs, so an apostrophe in a name broke out of the string; ui.js had already dropped inline handlers for this reason. The name now travels in data-county to one delegated listener. And route() decoded the hash unguarded: #county/%E0 threw URIError in boot and the list never rendered (reproduced in Chromium: 0 rows). It now falls back to the overview. Checked in Chromium: a row click still opens the county, the bad hash shows all 26, no page errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
The summary line already handled the singular; the timeline row, in render.py and its site.html mirror, always pluralised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
The nearby card rebuilt the a/<county>/<area>.html scheme by hand, so a change to area_path would have moved the pages and quietly broken every nearby link. Same target, one definition. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
…ains The render-level filter this PR added ran after label_repeats, so a fault following a pre-collection outage at the same spot kept a chain naming a leg the site lists nowhere, and every other caller of load_outages, the build summary and its empty-database guard included, still saw those events. They are now dropped once, in load_outages, after the merge (an event ends with its last member) and before the chains are labelled; the render helper goes. Found by review of this PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
- "up to 1 customers" on the county page's fault-spots card, the same plural slip fixed in the timeline. - _cell checked only the first character, so a formula behind a space or newline, which spreadsheet importers trim, went out live; the planned reason column is now under test too. - The area page's link into the app wrote the county into the hash raw, the one other producer of #county/ besides go(); it is now encoded and escaped. - The script test now also holds that something listens for the county rows' clicks, or a deleted listener would leave every row dead and CI green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
A build just after Dublin midnight on the 1st, from data to the night before, listed the new month under "to 30 Sep" on the county page, and the app headline read "0 faults and 0 planned outages" as though the month were over and quiet. The table's caveat now reads "no data yet", and the app says so in the headline and the county view and shows dashes, not zeros, in the tiles and the rows' counts. Owner's call; the note records it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
… month Review of this PR found the first cut used two rules: the page tested for an empty observed window, the app compared months with observed_month, and on a horizon landing exactly on Dublin midnight they disagreed, the app back to "so far: 0 faults". model.month_watched now decides it and ships it as D.nodata, observed_month is taken just before the horizon like partial_days, and the rest follows: - the county table shows dashes, not zeros, for such a month - the gate sentence says there is no data rather than promising a grade date - nothing is counted, nationally or per county, or filed in the shard for it, though a published restore time past the horizon used to slip in - CLAUDE.md gets its Settled row, and the merge comment says which end the collection-start filter uses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
A review of the last commit found it had moved observed_month a microsecond back but left the app's "so far" and "this month" keyed on it, so for the first hours of every month the app called September "so far" while the county page had closed it. "So far" now needs the newest listed month, with data in it. Also: - one model.overlaps rejects an empty window for county_month, the national row and the shard, instead of three copies of the guard - _daygate ships no grade date for a month with no data - the no-data table row carries the grade chip and its reason, and a test holds every row's cell count to the header - a data.js cached from before `nodata` falls back to comparing months - comments no longer restate the settled decision Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Slice 3 of the retroactive review, following #48, #51 and #52: a whole-file review of
esb_site/render.py,site.html, the three static templates,site.cssand__main__.py, then three reviews of this PR. Each commit holds one fix, and each fix's test was checked to fail without it.The fixes
model.load_outages, by the end the merge settles on and before the chains are labelled.=,+,-or@, or that opens with a tab or carriage return, now gets a leading apostrophe.--nowdropped an offset instead of converting it.onclickJS string. It now usesdata-countyand one delegated listener. The area page's link into the app encodes the county.#county/%E0) blanked the app. It now falls back to the overview.area_path.model.month_watcheddecides it once, and the app gets it asD.nodata.model.overlapsrejects an empty window, so nothing is counted or filed in such a month.notes/design-alignment.md, with a CLAUDE.md Settled row.JS was checked in Chromium with a normal build and one dated 00:20 on 1 October:
CI runs no JS, so the call sites are held by text tests.
Reviews of this PR
observed_monthchange left "so far" keyed on it, so at a month start the app called September "so far" while the page had closed it.model.overlaps.data.jswould bring the zeros back;Not taken:
notes/grading.mdnames.Effect on the site
Every published county and national figure is identical to
main. The area directory, area pages and search lose the 14 events over before collection began.Checks
ruff check: clean.unittest discoverwithESB_DATA_DIRset: 346 tests OK.🤖 Generated with Claude Code
https://claude.ai/code/session_01UqWuH6frirpbQDKnF5rEdT