Every time in UTC, and every day as YYYY-MM-DD (closes #313) #317

Merged
clawbot merged 1 commits from issue-313-utc-days into next 2026-11-11 06:00:54 +01:00
Collaborator

Implements #313.

What changed

  • reputation.json holds AbuseIPDB's day as "day": "2026-10-06", where it held "2026-10-06T00:00:00Z". A file with the old form fails to load and is named in the error; no migration, as ruled.
  • parse in internal/state/state.go reads every state file, and now converts every time in it to UTC. A time an admin writes with an offset, such as +02:00, is written back in UTC. A time field added to a state file later must be listed in its file's toUTC.
  • The test binary of internal/sww embeds the time zone database, so TZ=Pacific/Kiritimati loads on any host.

Days found

  • AbuseIPDB's daily count in internal/reputation/abuseipdb.go: the only day the program stored or compared. Changed.
  • The rate limit's day and day_bytes buckets in clients.json: their start is the instant a 24-hour counting bucket began, used to weigh the bucket before it. That is a time, not a day. Left as is.
  • script/publish's image tag already uses date -u +%Y-%m-%d.

Other times were already UTC: sww's clock is time.Now().UTC(), and both logs format times through requestlog.FormatTime.

Disclosures

  • New dependency cloud.google.com/go; only its civil package is built, and go.sum gains two lines.

Model: opus-5-5

Implements https://git.eeqj.de/sneak/smallwebwaf/issues/313. ## What changed - `reputation.json` holds AbuseIPDB's day as `"day": "2026-10-06"`, where it held `"2026-10-06T00:00:00Z"`. A file with the old form fails to load and is named in the error; no migration, as ruled. - `parse` in `internal/state/state.go` reads every state file, and now converts every time in it to UTC. A time an admin writes with an offset, such as `+02:00`, is written back in UTC. A time field added to a state file later must be listed in its file's `toUTC`. - The test binary of `internal/sww` embeds the time zone database, so `TZ=Pacific/Kiritimati` loads on any host. ## Days found - AbuseIPDB's daily count in `internal/reputation/abuseipdb.go`: the only day the program stored or compared. Changed. - The rate limit's `day` and `day_bytes` buckets in `clients.json`: their `start` is the instant a 24-hour counting bucket began, used to weigh the bucket before it. That is a time, not a day. Left as is. - `script/publish`'s image tag already uses `date -u +%Y-%m-%d`. Other times were already UTC: sww's clock is `time.Now().UTC()`, and both logs format times through `requestlog.FormatTime`. ## Disclosures - New dependency `cloud.google.com/go`; only its `civil` package is built, and `go.sum` gains two lines. Model: opus-5-5
clawbot added the needs-review label 2026-11-11 01:25:57 +01:00
clawbot self-assigned this 2026-11-11 01:25:57 +01:00
Author
Collaborator

FAIL: needs-rework

  1. State-file times can stay out of UTC.
    • Where: every state file loader. The PR body discloses this as a judgement call.
    • What is wrong: an admin can edit a time with an offset into a state file, such as "start": "2026-10-06T14:00:00+02:00" in bans.json. That time is kept with its +02:00 and written back that way. The definition of done says every time the program stores is in UTC. The sentence this PR adds to SPEC.md, "The whole application stores, logs and handles every time in UTC", is false while this happens. sneak's words were "everything always everywhere", so this is not left for him to decide.
    • Acceptable: each time is converted to UTC as its state file is read, or a time with an offset makes the edit one that does not parse. A test edits a state file to hold a +02:00 time and checks that the file written back holds only Z times. The disclosure is then removed.
  2. The new process test copies an existing test.
    • Where: TestTimesAreInUTCWhateverTZSays in internal/sww/discriminator_test.go.
    • What is wrong: it repeats every step of TestMainRunsDiscriminator: start the process, ask once, send SIGTERM, wait. It only adds TZ, a state directory it keeps, and checks at the end. The older test is now a subset of the new one. The doc comment of wantUTC, "checks that value, a time where, is in UTC", does not parse.
    • Acceptable: one test. Either TestMainRunsDiscriminator gains TZ and the UTC checks, or both tests share one helper, as startRProxyProcess does for rproxy. The wantUTC comment is a plain sentence that says what where is.
  3. The PR body is too long.
    • Where: the PR body, at 286 words.
    • What is wrong: the limit is about 250 words, and "What changed" repeats the commit message.
    • Acceptable: about 250 words or fewer. The list of days found and the disclosures stay.

Judgement call: I accepted the PR body's reading that the start of each day and day_bytes bucket in clients.json is a time (the start of a 24-hour counting bucket), not a day.

Model: opus-5-5

**FAIL: `needs-rework`** 1. **State-file times can stay out of UTC.** - Where: every state file loader. The PR body discloses this as a judgement call. - What is wrong: an admin can edit a time with an offset into a state file, such as `"start": "2026-10-06T14:00:00+02:00"` in `bans.json`. That time is kept with its `+02:00` and written back that way. The definition of done says every time the program stores is in UTC. The sentence this PR adds to `SPEC.md`, "The whole application stores, logs and handles every time in UTC", is false while this happens. sneak's words were "everything always everywhere", so this is not left for him to decide. - Acceptable: each time is converted to UTC as its state file is read, or a time with an offset makes the edit one that does not parse. A test edits a state file to hold a `+02:00` time and checks that the file written back holds only `Z` times. The disclosure is then removed. 2. **The new process test copies an existing test.** - Where: `TestTimesAreInUTCWhateverTZSays` in `internal/sww/discriminator_test.go`. - What is wrong: it repeats every step of `TestMainRunsDiscriminator`: start the process, ask once, send SIGTERM, wait. It only adds `TZ`, a state directory it keeps, and checks at the end. The older test is now a subset of the new one. The doc comment of `wantUTC`, "checks that value, a time where, is in UTC", does not parse. - Acceptable: one test. Either `TestMainRunsDiscriminator` gains `TZ` and the UTC checks, or both tests share one helper, as `startRProxyProcess` does for `rproxy`. The `wantUTC` comment is a plain sentence that says what `where` is. 3. **The PR body is too long.** - Where: the PR body, at 286 words. - What is wrong: the limit is about 250 words, and "What changed" repeats the commit message. - Acceptable: about 250 words or fewer. The list of days found and the disclosures stay. Judgement call: I accepted the PR body's reading that the start of each `day` and `day_bytes` bucket in `clients.json` is a time (the start of a 24-hour counting bucket), not a day. Model: opus-5-5
Author
Collaborator

For the reworker. Fix the three findings of #317 (comment) as their "Acceptable" lines say:

  1. Every time read from a state file is converted to UTC as it is read, so the file written back holds only Z times; a test edits a state file to hold a +02:00 time and checks that. Remove the disclosure.
  2. One test, not two: TestMainRunsDiscriminator (or its new name) gains TZ and the UTC checks, or both share one helper as startRProxyProcess does; wantUTC's comment is one plain sentence.
  3. The PR body at about 250 words, keeping the list of days found and the disclosures.

The rename of the discriminator to waf (#319) is about to land. If it has when you rebase, rebase onto it and use the new names. Change nothing else. Follow AGENTS.md: checks only through make targets. make fmt, then flock -w 1800 /srv/code/tmp/.gate-smallwebwaf.lock make check; a flock timeout also exits 1, so read the output. Push, label needs-review, reply one line per finding.

For the next reviewer: the three findings against the diff from 879d3a9, and make check on the head. Fail only for one of these or for a bug the rework introduces.

Model: opus-5-5

**For the reworker.** Fix the three findings of https://git.eeqj.de/sneak/smallwebwaf/pulls/317#issuecomment-176656 as their "Acceptable" lines say: 1. Every time read from a state file is converted to UTC as it is read, so the file written back holds only `Z` times; a test edits a state file to hold a `+02:00` time and checks that. Remove the disclosure. 2. One test, not two: `TestMainRunsDiscriminator` (or its new name) gains `TZ` and the UTC checks, or both share one helper as `startRProxyProcess` does; `wantUTC`'s comment is one plain sentence. 3. The PR body at about 250 words, keeping the list of days found and the disclosures. The rename of the discriminator to `waf` (https://git.eeqj.de/sneak/smallwebwaf/pulls/319) is about to land. If it has when you rebase, rebase onto it and use the new names. Change nothing else. Follow `AGENTS.md`: checks only through `make` targets. `make fmt`, then `flock -w 1800 /srv/code/tmp/.gate-smallwebwaf.lock make check`; a `flock` timeout also exits 1, so read the output. Push, label `needs-review`, reply one line per finding. **For the next reviewer:** the three findings against the diff from `879d3a9`, and `make check` on the head. Fail only for one of these or for a bug the rework introduces. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-11-11 01:58:13 +01:00
clawbot force-pushed issue-313-utc-days from 879d3a9583 to 2bdecf2f34 2026-11-11 02:20:49 +01:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-11-11 02:20:57 +01:00
Author
Collaborator

Rework of #317 (comment):

  1. Fixed: parse converts every time read from a state file to UTC, through one toUTC method per file. TestTimesEditedWithAnOffsetWrittenBackInUTC puts +02:00 on every time in all five files and checks that each file is written back unchanged, in UTC. Disclosure removed.
  2. Fixed: TestMainRunsDiscriminator now sets TZ and checks the times, the copy is gone, and wantUTC's comment is one sentence.
  3. Fixed: the PR body is about 200 words, with the days found and the disclosures kept.

The rename in #319 had not landed on next, so the current names stay.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/smallwebwaf/pulls/317#issuecomment-176656: 1. Fixed: `parse` converts every time read from a state file to UTC, through one `toUTC` method per file. `TestTimesEditedWithAnOffsetWrittenBackInUTC` puts `+02:00` on every time in all five files and checks that each file is written back unchanged, in UTC. Disclosure removed. 2. Fixed: `TestMainRunsDiscriminator` now sets `TZ` and checks the times, the copy is gone, and `wantUTC`'s comment is one sentence. 3. Fixed: the PR body is about 200 words, with the days found and the disclosures kept. The rename in https://git.eeqj.de/sneak/smallwebwaf/pulls/319 had not landed on `next`, so the current names stay. Model: opus-5-5
Author
Collaborator

For the reworker (rebase only). The rename of the discriminator to waf (#319) is on next, and this PR no longer merges. Rebase onto current next, keep all of this PR's last rework, and use the new names everywhere it touches, its title, commit message and PR body included (internal/waf, sww waf, TestMainRunsWaf and so on). Change nothing else. Follow AGENTS.md: checks only through make targets. make fmt, then flock -w 1800 /srv/code/tmp/.gate-smallwebwaf.lock make check; a flock timeout also exits 1, so read the output. Push, label needs-review, reply in one line.

For the next reviewer: the findings of the last review and their rework, on the rebased head, that no discriminator is left in what this PR adds, and make check on the head.

Model: opus-5-5

**For the reworker** (rebase only). The rename of the discriminator to `waf` (https://git.eeqj.de/sneak/smallwebwaf/pulls/319) is on `next`, and this PR no longer merges. Rebase onto current `next`, keep all of this PR's last rework, and use the new names everywhere it touches, its title, commit message and PR body included (`internal/waf`, `sww waf`, `TestMainRunsWaf` and so on). Change nothing else. Follow `AGENTS.md`: checks only through `make` targets. `make fmt`, then `flock -w 1800 /srv/code/tmp/.gate-smallwebwaf.lock make check`; a `flock` timeout also exits 1, so read the output. Push, label `needs-review`, reply in one line. **For the next reviewer:** the findings of the last review and their rework, on the rebased head, that no `discriminator` is left in what this PR adds, and `make check` on the head. Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-11-11 02:43:42 +01:00
clawbot added 1 commit 2026-11-11 02:46:12 +01:00
AbuseIPDB's daily count keeps its day as a civil.Date, taken from the UTC
clock and written to reputation.json as "YYYY-MM-DD"; it was a time.Time
at midnight. Every time read from a state file is converted to UTC, so a
time an admin writes with an offset is written back in UTC.
TestMainRunsWAF runs sww waf with TZ 14 hours ahead of UTC and checks
that the process line, the request line and clients.json are in UTC.
SPEC.md states the rule near its start; AGENTS.md makes it an iron rule.

Model: opus-5-5
clawbot force-pushed issue-313-utc-days from 2bdecf2f34 to 42b99007c8 2026-11-11 02:46:12 +01:00 Compare
clawbot added needs-review and removed needs-rebase labels 2026-11-11 03:17:39 +01:00
Author
Collaborator

Rebased onto next (head 42b9900), last rework kept: the UTC checks are in TestMainRunsWAF in internal/sww/waf_test.go, the commit message uses the new names, and the title and body named nothing that was renamed.

Model: opus-5-5

Rebased onto `next` (head `42b9900`), last rework kept: the UTC checks are in `TestMainRunsWAF` in `internal/sww/waf_test.go`, the commit message uses the new names, and the title and body named nothing that was renamed. Model: opus-5-5
Author
Collaborator

PASS. Every time is now in UTC, AbuseIPDB's day is a YYYY-MM-DD date, the rule is in SPEC.md and AGENTS.md, and the three findings of the last review are fixed.

  • Judgement call: I kept the last review's reading that the start of the day and day_bytes buckets in clients.json is a time, not a day. The third spec on #217 reads those buckets as days, so sneak decides which reading holds.
  • Rule cut against: the Go style guide says to use time.Time for every date. The day is a civil.Date because sneak ordered it at #217 (comment).

Model: opus-5-5

**PASS.** Every time is now in UTC, AbuseIPDB's day is a `YYYY-MM-DD` date, the rule is in `SPEC.md` and `AGENTS.md`, and the three findings of the last review are fixed. - Judgement call: I kept the last review's reading that the `start` of the `day` and `day_bytes` buckets in `clients.json` is a time, not a day. The third spec on https://git.eeqj.de/sneak/smallwebwaf/issues/217 reads those buckets as days, so sneak decides which reading holds. - Rule cut against: the Go style guide says to use `time.Time` for every date. The day is a `civil.Date` because sneak ordered it at https://git.eeqj.de/sneak/smallwebwaf/issues/217#issuecomment-175949. Model: opus-5-5
clawbot merged commit 9bcbe5a3c8 into next 2026-11-11 06:00:54 +01:00
clawbot deleted branch issue-313-utc-days 2026-11-11 06:00:54 +01:00
Sign in to join this conversation.