feat(statistics): present approved historical flow and baselines #172

Open
gabogg wants to merge 9 commits from feat/historical-flow-statistics into feat/historical-flow-publication
Owner

Summary

Draft for #165: the statistics deck reads approved historical hourly aggregates alongside local data, without double-counting.

  • It shows Complete/Partial/Missing coverage and hourly-source markers.
  • It marks peak, dwell, dayparts and 15/30-minute series as unavailable on hourly-only days.
  • It lets Complete, quality-checked, ordinary imported days feed count and hourly-flow Usual Weekday Baselines.

It was split out of #166. Specification: #165 and the historical-flow RFC. Holiday/event presentation coordinates with #161.

Stacked on feat/historical-flow-publication (#164 draft). Only a placeholder commit is on this branch; implementation has not started.

Architectural impact (planned)

  • Read-only statistics queries combine local rollups/events with approved aggregates using #164's precedence.
  • Response schemas gain source/coverage markers and unavailable-measure reasons.
  • Deck rendering for those markers.

Verification

  • Repository/service/API and deck tests for full/partial/missing days, local/imported mixing, markers, unavailable measures, baseline eligibility, historical corrections and no double-counting.
  • Ruff, scripts/check_docs.py, full pytest.

Checklist

  • #164 merged.
  • Implement #165.
  • Review passes.

Issues closed on merge

Closes #165

🤖 Generated with Claude Code

## Summary Draft for #165: the statistics deck reads approved historical hourly aggregates alongside local data, without double-counting. - It shows Complete/Partial/Missing coverage and hourly-source markers. - It marks peak, dwell, dayparts and 15/30-minute series as unavailable on hourly-only days. - It lets Complete, quality-checked, ordinary imported days feed count and hourly-flow Usual Weekday Baselines. It was split out of #166. Specification: #165 and the historical-flow RFC. Holiday/event presentation coordinates with #161. Stacked on `feat/historical-flow-publication` (#164 draft). Only a placeholder commit is on this branch; implementation has not started. ## Architectural impact (planned) - Read-only statistics queries combine local rollups/events with approved aggregates using #164's precedence. - Response schemas gain source/coverage markers and unavailable-measure reasons. - Deck rendering for those markers. ## Verification - [ ] Repository/service/API and deck tests for full/partial/missing days, local/imported mixing, markers, unavailable measures, baseline eligibility, historical corrections and no double-counting. - [ ] Ruff, `scripts/check_docs.py`, full pytest. ## Checklist - [ ] #164 merged. - [ ] Implement #165. - [ ] Review passes. ## Issues closed on merge Closes #165 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Placeholder commit so the stacked draft PR exists before implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refactor(ui): fold diagnostic decks into one DIAGNOSTICS menu
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m9s
3ce41dff63
The admin deck selector carried seven entries. SYSTEM_DIAG, API_CONSOLE and
EVENT_LOGS now share a single "[ F4: DIAGNOSTICS ▾ ]" entry that opens a
menu, making room for the historical-flow import deck (#170) and reducing
clutter in the main tab strip.

- New DeckMenu module (src/ui/deck_menu.js): menu rendered outside the
  horizontally scrolling selector with fixed positioning clamped to the
  viewport, so the strip's overflow never clips it; follows the button on
  scroll/resize. Keyboard support: ArrowUp/Down/Home/End, Escape returns
  focus, Tab or an outside click closes. Items are menuitemradio with
  aria-checked; the button shows the active deck (e.g. DIAGNOSTICS:
  API_CONSOLE) and is highlighted while any grouped deck is active.
- F4/F6/F7 shortcuts still switch directly to each deck; RBAC unchanged.
- Deck selector buttons no longer wrap on narrow screens: the strip scrolls
  horizontally instead.
- Node tests for the menu (grouping, keyboard, positioning, active sync).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chore: open draft for #108 (call dated overrides schedule exceptions)
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m11s
8537247eae
Placeholder commit so the draft PR exists before implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chore: open draft for #113 (each business day remembers its schedule)
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m14s
bafba281ae
Placeholder commit so the draft PR exists before implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Placeholder commit so the draft PR exists before implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(agents): group feature deliveries into milestones
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m8s
b0bef9dde3
Define when to create a Forgejo milestone (an umbrella split into two or
more issues, or a delivery spanning two or more PRs), how to name and
describe it, which issues and PRs join it (children, review follow-ups,
maintainer-declared prerequisites, feature-serving PRs, split scope), what
stays out, and when to close it. Add tea commands, an AGENTS.md pointer, a
docs index entry and the PR-protocol step that assigns a PR its issue's
milestone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(agents): group feature deliveries into milestones (#179)
All checks were successful
CI / lint-and-test (push) Successful in 2m6s
277aaeb2b5
fix(occupancy): address review pass 2 on historical flow staging (#162)
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m21s
93df647257
- P2 (standards): decode the statisticsTotalNumByTime envelope and rows in
  the client layer. New app/clients/people_counting.py returns typed
  PeopleCountingPage/HourlyPeopleCount (numeric strings, naive facility
  times, malformed-row count, failure reasons); ArtemisClient takes
  datetimes and formats the request. The service keeps only domain checks
  (requested camera, whole hour, inside the range).
- P2 (spec): each fetch records the reset time its day ranges used and
  each request its business day; the month summary cuts days with the
  view's recorded reset and matches attempts by business day, so a later
  reset change no longer moves staged hours or hides requests. The summary
  reports the reset used and whether fetches in view disagree.
- P2 (spec): a revision's summary covers only fetches made before the next
  revision existed, for cameras, attempts and the fetch list.
- P3: MONTH_PATTERN is defined once in facility_time and reused by the
  API schemas.
- Tests: decoder typing and failure pages, reset change after a fetch,
  older revision unaffected by later fetches; the fake HikCentral now
  emits vendor JSON through the real decoder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(occupancy): retrieve and stage historical HikCentral flow (#166)
All checks were successful
CI / lint-and-test (push) Successful in 2m22s
f5732e85ca
fix(ui): keep the DIAGNOSTICS menu on screen and close it on F-keys
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m20s
ce9204907e
Review pass 1 on #173:
- P2: the menu could extend below a short viewport. New menuPlacement()
  opens it below the button, or above when that side has more room and
  it does not fit below, and caps max-height to the visible space on the
  chosen side so the menu scrolls instead of overflowing.
- P2: pressing F4/F6/F7 with the menu open switched decks but left the
  menu over the selected deck. syncActive(), called on every deck switch,
  now always closes the menu.
- Tests for below/above/scroll placement, the short-viewport flip and the
  F-key close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chore(schedule): label dated overrides as schedule exceptions
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m15s
5322763cf6
Merge remote-tracking branch 'origin/master' into chore/schedule-exception-naming
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m26s
4034c4216e
# Conflicts:
#	docs/api/README.md
refactor(ui): fold diagnostic decks into one DIAGNOSTICS menu (#173)
All checks were successful
CI / lint-and-test (push) Successful in 2m43s
fb89880df1
fix(schedule): address first-pass exception naming review
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m30s
fdfad26430
fix(schedule): call dated overrides schedule exceptions (#175)
All checks were successful
CI / lint-and-test (push) Successful in 2m35s
4029c7955a
feat(schedule): record business-day schedules and audit corrections
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m47s
0e65494239
fix(schedule): address first review findings
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m35s
69ba31a326
feat(schedule): each business day remembers the schedule it was measured under (#176)
All checks were successful
CI / lint-and-test (push) Successful in 2m35s
b864399389
feat(statistics): holiday and event context for investor analytics (#161)
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m59s
e13e3965f5
- Differentiate holiday identity from schedule exceptions (ScheduleException vs Holiday).
- Add event annotations support with timed intervals and all-day date ranges.
- Implement event overlaps across business day cycle boundaries with half-open intervals.
- Exclude holidays and event days from proportional multiplier automatic learning and usual weekday baselines.
- Require audit reason for holiday classification and event changes affecting completed business days.
- Add audit logging for holiday classification and event lifecycle (CREATE, UPDATE, DELETE).
- Expose CRUD and audit endpoints under /api/occupancy/events and /api/occupancy/holidays.
- Support event viewing under /api/statistics/events and context-rich exports in /api/statistics/export.
- Update deck views (day, week, month) to display holiday hours, event annotations, and context lists.
- Add comprehensive test coverage in tests/test_holiday_event_context.py.
- Combine local observations and approved hourly flow aggregates without double counting
- Enforce local precedence per camera-hour in count and series queries
- Mark peak, dwell, dayparts, and sub-hourly series as unavailable on hourly-only days
- Support Usual Weekday Baselines from complete, trusted imported days
- Exclude approved historical days from calibration history and auto calibration
- Surface source and coverage indicators in frontend day view and i18n
- Add unit, repository, service, API, and frontend tests
gabogg changed title from WIP: feat(statistics): present approved historical flow and baselines to feat(statistics): present approved historical flow and baselines 2026-10-02 14:08:39 +00:00
Author
Owner

Marked blocked, at the maintainer's request (2026-10-02). The review pass waits until this PR's base is real:

  1. #178 (holiday and event context) must finish its review and merge into master. This PR builds on #178's code, so reviewing it first would risk findings going stale if #178 changes in review.
  2. #170 (curation) and #171 (publication) must be implemented. Both are still draft placeholders, and this PR stacks on them. Approved historical flow comes from those PRs, so this PR may need to adjust once #171's publication exists.

Unblock once #178 has merged, master has been carried up the stack, and #171 has real code. This PR then gets its first review pass.

Current state: the branch includes master as of b48940e, and its diff against #171 is 14 files (+1464/−90).

🤖 Generated with Claude Code

Marked `blocked`, at the maintainer's request (2026-10-02). The review pass waits until this PR's base is real: 1. **#178** (holiday and event context) must finish its review and merge into `master`. This PR builds on #178's code, so reviewing it first would risk findings going stale if #178 changes in review. 2. **#170** (curation) and **#171** (publication) must be implemented. Both are still draft placeholders, and this PR stacks on them. Approved historical flow comes from those PRs, so this PR may need to adjust once #171's publication exists. Unblock once #178 has merged, `master` has been carried up the stack, and #171 has real code. This PR then gets its first review pass. Current state: the branch includes `master` as of b48940e, and its diff against #171 is 14 files (+1464/−90). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

Unblocked: #178 merged (b64e805), and master is merged into #170 and #171. Merging origin/feat/historical-flow-publication into this branch conflicts in statistics_controller.py (1 hunk), occupancy_repository.py (2) and analytics_service.py (3). #178's holiday and event context overlaps the historical-flow statistics here. That needs a domain decision, so I aborted the merge and left it to this PR's agent.

Unblocked: #178 merged (`b64e805`), and master is merged into #170 and #171. Merging `origin/feat/historical-flow-publication` into this branch conflicts in `statistics_controller.py` (1 hunk), `occupancy_repository.py` (2) and `analytics_service.py` (3). #178's holiday and event context overlaps the historical-flow statistics here. That needs a domain decision, so I aborted the merge and left it to this PR's agent.
# Conflicts:
#	app/controllers/statistics_controller.py
#	app/db/occupancy_repository.py
#	app/services/analytics_service.py
Author
Owner

Merge Conflict Resolution: origin/feat/historical-flow-publication into feat/historical-flow-statistics

Merged origin/feat/historical-flow-publication (incorporating #178 holiday and event context into investor analytics) into feat/historical-flow-statistics. All conflicts were resolved preserving both domain features:

  1. app/controllers/statistics_controller.py (1 hunk)

    • In get_presenter_hourly_series, retained both closed_day_config_async(day) configuration resolution (cfg) from #178 and the integer cast bucket_minutes=int(bucket_minutes) from #165, passing both to analytics_service.get_hourly_timeseries_async.
  2. app/db/occupancy_repository.py (2 hunks)

    • Hunk 1 (get_counted_camera_flow_async): Maintained the approved camera hours CTE resolution from #165 while adopting g.resource_group_name AS camera_group (from #168/#178) instead of the obsolete c.zone_name across both the local-only and resolved-CTE branches.
    • Hunk 2 (get_trusted_calibration_history_async): Retained the dynamic reset time resolution and timed-event date exclusion from #178, updated holiday identification to query occupancy_business_day_schedules WHERE is_holiday = 1 as the single source of truth, and preserved strict calibration exclusion for imported/mixed days via cycle_date NOT IN (SELECT business_day FROM flow_history_approved_days).
  3. app/services/analytics_service.py (3 hunks)

    • Hunk 1 (get_statistics_summary_async): Kept the structured summary comparison variables initialization from #178 while safely handling historical days where peak_people_inside is None.
    • Hunk 2 (get_statistics_daily_series_async): Combined the holiday calendar (sched = calendar.schedule_for(day)) and event summaries from #178 with historical flow day resolution (app_day, is_hourly_source, source, coverage, and get_counted_day_flow_async). Approved historical days now carry full holiday and event context identically to local days.
    • Hunk 3 (get_dwell_dayparts_async): Integrated the approved day check with _compute_dayparts_for_day_async, yielding DwellDay(date=current_day, dayparts=[], unavailable_reason="HOURLY_AGGREGATE_ONLY") on approved historical days.

Verification

  • Added test_historical_holiday_day_carries_holiday_and_event_context to tests/test_historical_flow_statistics.py verifying that historical days carry holiday and event context in both hourly and daily time-series endpoints.
  • ruff check . passed cleanly (no issues found).
  • ruff format --check . passed cleanly (152 files formatted).
  • python3 scripts/check_docs.py passed cleanly (42 Markdown files and 89 HTTP operations checked).
  • node --test tests/frontend/*.test.js passed 100% green (245/245 tests passed).
  • pytest passed 100% green (565/565 tests passed).
### Merge Conflict Resolution: `origin/feat/historical-flow-publication` into `feat/historical-flow-statistics` Merged `origin/feat/historical-flow-publication` (incorporating #178 holiday and event context into investor analytics) into `feat/historical-flow-statistics`. All conflicts were resolved preserving both domain features: 1. **`app/controllers/statistics_controller.py` (1 hunk)** - In `get_presenter_hourly_series`, retained both `closed_day_config_async(day)` configuration resolution (`cfg`) from #178 and the integer cast `bucket_minutes=int(bucket_minutes)` from #165, passing both to `analytics_service.get_hourly_timeseries_async`. 2. **`app/db/occupancy_repository.py` (2 hunks)** - **Hunk 1 (`get_counted_camera_flow_async`)**: Maintained the approved camera hours CTE resolution from #165 while adopting `g.resource_group_name AS camera_group` (from #168/#178) instead of the obsolete `c.zone_name` across both the local-only and resolved-CTE branches. - **Hunk 2 (`get_trusted_calibration_history_async`)**: Retained the dynamic reset time resolution and timed-event date exclusion from #178, updated holiday identification to query `occupancy_business_day_schedules WHERE is_holiday = 1` as the single source of truth, and preserved strict calibration exclusion for imported/mixed days via `cycle_date NOT IN (SELECT business_day FROM flow_history_approved_days)`. 3. **`app/services/analytics_service.py` (3 hunks)** - **Hunk 1 (`get_statistics_summary_async`)**: Kept the structured summary comparison variables initialization from #178 while safely handling historical days where `peak_people_inside` is `None`. - **Hunk 2 (`get_statistics_daily_series_async`)**: Combined the holiday calendar (`sched = calendar.schedule_for(day)`) and event summaries from #178 with historical flow day resolution (`app_day`, `is_hourly_source`, `source`, `coverage`, and `get_counted_day_flow_async`). Approved historical days now carry full holiday and event context identically to local days. - **Hunk 3 (`get_dwell_dayparts_async`)**: Integrated the approved day check with `_compute_dayparts_for_day_async`, yielding `DwellDay(date=current_day, dayparts=[], unavailable_reason="HOURLY_AGGREGATE_ONLY")` on approved historical days. #### Verification - Added `test_historical_holiday_day_carries_holiday_and_event_context` to `tests/test_historical_flow_statistics.py` verifying that historical days carry holiday and event context in both hourly and daily time-series endpoints. - `ruff check .` passed cleanly (no issues found). - `ruff format --check .` passed cleanly (152 files formatted). - `python3 scripts/check_docs.py` passed cleanly (42 Markdown files and 89 HTTP operations checked). - `node --test tests/frontend/*.test.js` passed 100% green (245/245 tests passed). - `pytest` passed 100% green (565/565 tests passed).
Author
Owner

Merge Conflict Resolution: PR #171 (feat/historical-flow-publication @ 674f266) into feat/historical-flow-statistics

Merged PR #171 (carrying PR #170 curation draft workspace) into feat/historical-flow-statistics. Conflicts were resolved preserving both domain features:

  1. app/db/database.py: Retained curation draft tables (#163: flow_history_curation_drafts, flow_history_curation_days, flow_history_curation_zero_confirmations, flow_history_curation_audit) alongside approved flow tables (#164, #165).
  2. app/schemas/flow_history.py: Kept ApprovedMonthRecord, curation draft schemas (CurationDaySummary, CurationDraftDetail, etc.), and approved flow records (ApprovedDayRecord, ApprovedHourRecord).
  3. app/db/flow_history_repository.py: Integrated both Approved Working Storage repository methods (publish_approved_month_async, get_approved_day_async, etc.) and Curation Drafts repository methods (create_or_get_curation_draft_async, _compute_day_coverage, etc.).
  4. app/db/occupancy_repository.py: In get_trusted_calibration_history_async, preserved pending change reeval logic (#177) and retained strict calibration exclusion for imported/mixed days (AND cycle_date NOT IN (SELECT business_day FROM flow_history_approved_days)).

Verification

  • ruff check: 0 issues
  • ruff format --check: 156 files formatted
  • python3 scripts/check_docs.py: 43 Markdown files and 99 HTTP operations consistent
  • node --test tests/frontend/*.test.js: 250 tests passed
  • pytest: 623 passed
### Merge Conflict Resolution: PR #171 (feat/historical-flow-publication @ 674f266) into feat/historical-flow-statistics Merged PR #171 (carrying PR #170 curation draft workspace) into feat/historical-flow-statistics. Conflicts were resolved preserving both domain features: 1. **app/db/database.py**: Retained curation draft tables (#163: `flow_history_curation_drafts`, `flow_history_curation_days`, `flow_history_curation_zero_confirmations`, `flow_history_curation_audit`) alongside approved flow tables (#164, #165). 2. **app/schemas/flow_history.py**: Kept `ApprovedMonthRecord`, curation draft schemas (`CurationDaySummary`, `CurationDraftDetail`, etc.), and approved flow records (`ApprovedDayRecord`, `ApprovedHourRecord`). 3. **app/db/flow_history_repository.py**: Integrated both Approved Working Storage repository methods (`publish_approved_month_async`, `get_approved_day_async`, etc.) and Curation Drafts repository methods (`create_or_get_curation_draft_async`, `_compute_day_coverage`, etc.). 4. **app/db/occupancy_repository.py**: In `get_trusted_calibration_history_async`, preserved pending change reeval logic (#177) and retained strict calibration exclusion for imported/mixed days (`AND cycle_date NOT IN (SELECT business_day FROM flow_history_approved_days)`). #### Verification - ruff check: 0 issues - ruff format --check: 156 files formatted - python3 scripts/check_docs.py: 43 Markdown files and 99 HTTP operations consistent - node --test tests/frontend/*.test.js: 250 tests passed - pytest: 623 passed
Author
Owner

Merged PR #171 (feat/historical-flow-publication) into #172.

Conflict Resolutions

  1. app/schemas/flow_history.py:
    • Unified ApprovedDayRecord and ApprovedHourRecord contracts. Preserved default values (HISTORICAL_FLOW_SOURCE) and optional fields (id, month, business_day) needed by presentation routes and statistics tests, while incorporating ApprovedDayDetail and ApprovedMonthDetail.
  2. app/services/occupancy_service.py:
    • Harmonized calibration learning eligibility: combined is_imported (schedule source), has_imported_flow (imported/mixed flow check), and has_approved_flow to ensure no approved or imported historical flow can ever update active exit multiplier k.
  3. app/db/occupancy_repository.py:
    • In get_trusted_calibration_history_conn_async and cycle ingress queries, strictly excluded cycles with source = 'IMPORTED' in schedules and any day in flow_history_approved_days from trusted history.
  4. app/db/flow_history_repository.py:
    • Removed duplicate stub methods from the draft milestone. Enhanced get_approved_day_async to polymorphically support both single-argument (business_day: str) (used by analytics) and two-argument (month: str, business_day: date) (used by publication/curation), returning ApprovedDayDetail with validated datetime.date types. Retained publish_month_async, list_approved_months_async, and range queries.

All 632 pytest tests and 250 node tests pass cleanly.

Merged PR #171 (feat/historical-flow-publication) into #172. ### Conflict Resolutions 1. **`app/schemas/flow_history.py`**: - Unified `ApprovedDayRecord` and `ApprovedHourRecord` contracts. Preserved default values (`HISTORICAL_FLOW_SOURCE`) and optional fields (`id`, `month`, `business_day`) needed by presentation routes and statistics tests, while incorporating `ApprovedDayDetail` and `ApprovedMonthDetail`. 2. **`app/services/occupancy_service.py`**: - Harmonized calibration learning eligibility: combined `is_imported` (schedule source), `has_imported_flow` (imported/mixed flow check), and `has_approved_flow` to ensure no approved or imported historical flow can ever update active exit multiplier k. 3. **`app/db/occupancy_repository.py`**: - In `get_trusted_calibration_history_conn_async` and cycle ingress queries, strictly excluded cycles with `source = 'IMPORTED'` in schedules and any day in `flow_history_approved_days` from trusted history. 4. **`app/db/flow_history_repository.py`**: - Removed duplicate stub methods from the draft milestone. Enhanced `get_approved_day_async` to polymorphically support both single-argument `(business_day: str)` (used by analytics) and two-argument `(month: str, business_day: date)` (used by publication/curation), returning `ApprovedDayDetail` with validated `datetime.date` types. Retained `publish_month_async`, `list_approved_months_async`, and range queries. All 632 pytest tests and 250 node tests pass cleanly.
Author
Owner

#171 pass-1 fixes are in progress after the #170 pass-2 handoff. Publication now retains snapshots keyed by (month, revision); current readers select MAX(revision) per month, and approved hours retain is_unresolved. I will merge the completed, tested #171 fixes into #172 as requested and adapt any integration conflicts. Please leave the statistics worktree clean for that handoff.

#171 pass-1 fixes are in progress after the #170 pass-2 handoff. Publication now retains snapshots keyed by (month, revision); current readers select MAX(revision) per month, and approved hours retain is_unresolved. I will merge the completed, tested #171 fixes into #172 as requested and adapt any integration conflicts. Please leave the statistics worktree clean for that handoff.
Author
Owner

Merged #171 pass-1 fixes (e0d10d2) into #172 at d8f3c48 and pushed the branch. Resolved all four conflicts while retaining the #170/#171 curation lifecycle, typed publication writer, retained revision reads, independent quality flags, unresolved hours and purely-local calibration eligibility. Updated statistics readers to select current resolved revisions, moved statistics seed writes into test fixtures, and added a regression covering month/day/hour/range/count/camera/bucket/quality readers across retained revisions. Verification: 673 pytest tests and 252 frontend tests passed; Ruff, documentation checks (43 Markdown files, 102 HTTP operations) and installed formatting/metadata hooks passed. #171 requests review pass 2 separately.

Merged #171 pass-1 fixes (e0d10d2) into #172 at d8f3c48 and pushed the branch. Resolved all four conflicts while retaining the #170/#171 curation lifecycle, typed publication writer, retained revision reads, independent quality flags, unresolved hours and purely-local calibration eligibility. Updated statistics readers to select current resolved revisions, moved statistics seed writes into test fixtures, and added a regression covering month/day/hour/range/count/camera/bucket/quality readers across retained revisions. Verification: 673 pytest tests and 252 frontend tests passed; Ruff, documentation checks (43 Markdown files, 102 HTTP operations) and installed formatting/metadata hooks passed. #171 requests review pass 2 separately.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/historical-flow-statistics:feat/historical-flow-statistics
git switch feat/historical-flow-statistics

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch feat/historical-flow-publication
git merge --no-ff feat/historical-flow-statistics
git switch feat/historical-flow-statistics
git rebase feat/historical-flow-publication
git switch feat/historical-flow-publication
git merge --ff-only feat/historical-flow-statistics
git switch feat/historical-flow-statistics
git rebase feat/historical-flow-publication
git switch feat/historical-flow-publication
git merge --no-ff feat/historical-flow-statistics
git switch feat/historical-flow-publication
git merge --squash feat/historical-flow-statistics
git switch feat/historical-flow-publication
git merge --ff-only feat/historical-flow-statistics
git switch feat/historical-flow-publication
git merge feat/historical-flow-statistics
git push origin feat/historical-flow-publication
Sign in to join this conversation.
No reviewers
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gabogg/hikcentral!172
No description provided.