feat(schedule): each business day remembers the schedule it was measured under #176

Merged
gabogg merged 4 commits from feat/business-day-schedule-records into master 2026-09-29 15:45:57 +00:00
Owner

Summary

Implements #113: each business day keeps the opening status, hours, source, and exception name resolved when its reset begins. Weekly and dated exception edits no longer change a started day's schedule. Older unrecorded days explicitly fall back to the current plan until an admin stamps or corrects them.

The schedule section now lets admins inspect a day and its audit history, stamp every completed day between the first and last counted event, and correct completed days with a reason. Overwrite requires a selected range and confirmation. Corrections change statistical interpretation immediately; calibration uses the original recorded schedule. Reset-time edits still recut historical business-day boundaries; date-effective reset records are tracked separately in #114.

Architectural impact

  • Added business-day schedule and audit tables, with atomic freeze, stamp and correction writes.
  • Extended the shared schedule reader to prefer recorded days across statistics and live scheduling. Calibration retains the first schedule value recorded for a day after corrections.
  • The monitor freezes a new business day at reset; service methods freeze the current day before schedule edits.
  • Added admin API contracts and schedule-section controls, preserving IMPORTED as a source for later historical-flow work.

Verification

  • Eight focused tests cover freeze before edits, unrecorded fallback, zero-count day stamping, idempotent stamp, range overwrite and audit, correction and statistics/live consistency, calibration history, and API authorization.
  • Full pytest suite passed in the pre-commit hook after the review fixes.
  • Ruff lint and format, JavaScript syntax, python3 scripts/check_docs.py, and git diff --check passed.

Checklist

  • Implement #113.
  • Address all first-pass review findings and request a second pass.
  • Complete review passes per docs/standards/git-and-workflow.md.

Issues closed on merge

Closes #113

## Summary Implements #113: each business day keeps the opening status, hours, source, and exception name resolved when its reset begins. Weekly and dated exception edits no longer change a started day's schedule. Older unrecorded days explicitly fall back to the current plan until an admin stamps or corrects them. The schedule section now lets admins inspect a day and its audit history, stamp every completed day between the first and last counted event, and correct completed days with a reason. Overwrite requires a selected range and confirmation. Corrections change statistical interpretation immediately; calibration uses the original recorded schedule. Reset-time edits still recut historical business-day boundaries; date-effective reset records are tracked separately in #114. ## Architectural impact - Added business-day schedule and audit tables, with atomic freeze, stamp and correction writes. - Extended the shared schedule reader to prefer recorded days across statistics and live scheduling. Calibration retains the first schedule value recorded for a day after corrections. - The monitor freezes a new business day at reset; service methods freeze the current day before schedule edits. - Added admin API contracts and schedule-section controls, preserving `IMPORTED` as a source for later historical-flow work. ## Verification - [x] Eight focused tests cover freeze before edits, unrecorded fallback, zero-count day stamping, idempotent stamp, range overwrite and audit, correction and statistics/live consistency, calibration history, and API authorization. - [x] Full pytest suite passed in the pre-commit hook after the review fixes. - [x] Ruff lint and format, JavaScript syntax, `python3 scripts/check_docs.py`, and `git diff --check` passed. ## Checklist - [x] Implement #113. - [x] Address all first-pass review findings and request a second pass. - [ ] Complete review passes per `docs/standards/git-and-workflow.md`. ## Issues closed on merge Closes #113
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>
gabogg changed title from WIP: feat(schedule): each business day remembers the schedule it was measured under to feat(schedule): each business day remembers the schedule it was measured under 2026-09-28 17:43:36 +00:00
Author
Owner

Code review, pass 1 (origin/master...0e65494, spec #113)

Result: no P1s. 4 P2s (2 Standards, 2 Spec) and 11 P3s (8 Standards, 3 Spec). This is the first pass, so every finding gets fixed on the branch.

Verification: pytest 458 passed, frontend 242 passed, ruff clean, CI green. The branch is based on current master (4029c79) and merges cleanly.

Standards

Clean: require_admin protects the audit, stamp and correct routes. Errors use VALIDATION_ERROR per code-standards §3. All SQL is in OccupancyRepository. Stamp and correct each write the record and its audit row in one BEGIN IMMEDIATE. The migration is idempotent with CHECK constraints. The audit list escapes values before innerHTML. Tests use real sqlite and the ASGI client. EN and ES keys are complete.

P2

  1. Glossary clash (app/static/js/i18n.js:169). The ES stampDaysHelp says "los días cerrados" where it means completed days. CONTEXT.md defines Closed Day as a day the schedule declares closed, so the help text reads as the opposite. Use "días completados".
  2. Labels not uppercase (app/static/index.html:796-799). The correction form reuses openTableHeader, openTimeTableHeader and closeTimeTableHeader, which translate to mixed case ("Opening", "Apertura"). The <label>s have no uppercase class, but ui-design-guidelines §3.2 requires uppercase labels. The "is exception" checkbox also reuses the plural tab title subtabScheduleExceptions. Give it its own singular key.

P3 (judgement calls)
3. Duplicated Code.

  • date.fromisoformat(facility_cycle_bounds(x, reset).label) appears at occupancy_service.py:262,275,290,359,386,387. Use facility_time.active_business_day().
  • The upsert SQL is copied at occupancy_repository.py:889 and :946.
  • The row→BusinessDaySchedule mapping exists in both the service (~230) and the repository (:49).
  1. Duplicated Code / Middle Man. The controller builds a BusinessDaySchedule(source="MANUAL", recorded=True) (occupancy_controller.py:277), and the service builds the same object again (occupancy_service.py:367). Pass only the corrected fields.
  2. Shotgun Surgery. Four controllers repeat "freeze today before a schedule edit" (occupancy_controller.py:132,190,333,358). Move it next to the writes in the service, so a new edit route can't skip it.
  3. Primitive Obsession. The source list is defined three times: ScheduleSource (facility_time.py:49), ScheduleSourceValue (occupancy_models.py:324) and the DB CHECK. Keep one source of truth.
  4. Performance. Every call to get_active_schedule_info_async runs ensure_* and then loads the full calendar, including every record. Loops call it once per cycle (analytics_service.py:929,1038, occupancy_service.py:1467), and on every event (:717), so the cost grows with history. The monitor also reads the reset time on every 1 s tick (monitor_service.py:~98).
  5. Missing annotation. last_schedule_day = None in monitor_service.py should be annotated date | None.
  6. Hardcoded Spanish. "Excepción de horario" and the Spanish day_names moved into the service (occupancy_service.py:226,391) unchanged. This predates the PR and overlaps #73 and #184.
  7. Missing test. No test checks that a non-admin gets 403 on the stamp, correct or audit routes.

Spec

Checked and correct:

  • The monitor freezes the day on its first loop and on every business-day change (monitor_service.py:103-108).
  • Business days go through facility_cycle_bounds, so an edit between 00:00 and the reset freezes the previous day.
  • The weekly, exception and config endpoints freeze the current day before they write.
  • No code path resolves a day's schedule outside schedule_for.
  • Overwrite requires a range plus confirmation. Corrections are limited to past days.
  • Audit rows hold actor, reason, and old and new values.
  • The UI uses the Schedule Exception wording and warns that changing the reset time re-cuts history.

P2
11. (a) The default stamp skips days with no counts. Spec: "by default fills only days that have no record" and "records can exist for any date, not only days with counted data". With no dates given, the service keeps only has_data days (occupancy_service.py:326). Closed and outage days with zero counts stay unrecorded, so a later weekly edit reclassifies them. That breaks "Editing the weekly schedule … never changes a … past day's classification". Default to the full span, including days with no data.
12. (a) The one-reader test never touches statistics. Spec: "one-reader consistency (statistics and live view agree for the same day)". The test compares ScheduleCalendar with get_active_schedule_info_async only. Add an assertion through an analytics_service path: the Closed Day list (analytics_service.py:439/811), or dwell and dayparts (:929/1038).

P3
13. (a) Automatic freezes are not audit-logged. Spec: "every stamp or correction is audit-logged". ensure_business_day_schedule_record_async (occupancy_repository.py:~838) writes no audit row. After a restart that spans the reset, the day is recorded late with the plan in force at that moment, and nothing shows it was late. Add an audit row with actor system, or a recorded-at timestamp that shows the lateness.
14. (c) A correction can still reach calibration. Spec: "a correction never re-runs an audit or feeds old data into the current calibration". The completed-cycle audit reads the reader (occupancy_service.py:1214). If an admin corrects yesterday before the auto-audit runs, the corrected hours feed k. Pin the audit to the hours recorded at freeze time, or document this window.
15. (b) Scope creep, reasonable. The PR adds a GET /schedule/days/{d} route, an /audit route, a 10-year cap on stamp ranges, and schedule_source / schedule_recorded fields in the live info. The API docs count jumps from 66 to 80. The old 66 was stale, and only 4 routes are new.

Summary

  • Standards: 2 P2s, 8 P3s. The worst is the ES "días cerrados" clash with the Closed Day term.
  • Spec: 2 P2s, 3 P3s. The worst is that the default stamp skips zero-count days, which a later weekly edit can reclassify.

🤖 Generated with Claude Code

## Code review, pass 1 (`origin/master...0e65494`, spec #113) Result: **no P1s. 4 P2s (2 Standards, 2 Spec) and 11 P3s (8 Standards, 3 Spec).** This is the first pass, so every finding gets fixed on the branch. Verification: pytest 458 passed, frontend 242 passed, ruff clean, CI green. The branch is based on current master (4029c79) and merges cleanly. ## Standards **Clean:** `require_admin` protects the audit, stamp and correct routes. Errors use `VALIDATION_ERROR` per code-standards §3. All SQL is in `OccupancyRepository`. Stamp and correct each write the record and its audit row in one `BEGIN IMMEDIATE`. The migration is idempotent with CHECK constraints. The audit list escapes values before `innerHTML`. Tests use real sqlite and the ASGI client. EN and ES keys are complete. **P2** 1. **Glossary clash (`app/static/js/i18n.js:169`).** The ES `stampDaysHelp` says "los días **cerrados**" where it means completed days. CONTEXT.md defines Closed Day as a day the schedule declares closed, so the help text reads as the opposite. Use "días completados". 2. **Labels not uppercase (`app/static/index.html:796-799`).** The correction form reuses `openTableHeader`, `openTimeTableHeader` and `closeTimeTableHeader`, which translate to mixed case ("Opening", "Apertura"). The `<label>`s have no `uppercase` class, but ui-design-guidelines §3.2 requires uppercase labels. The "is exception" checkbox also reuses the plural tab title `subtabScheduleExceptions`. Give it its own singular key. **P3 (judgement calls)** 3. **Duplicated Code.** - `date.fromisoformat(facility_cycle_bounds(x, reset).label)` appears at `occupancy_service.py:262,275,290,359,386,387`. Use `facility_time.active_business_day()`. - The upsert SQL is copied at `occupancy_repository.py:889` and `:946`. - The row→`BusinessDaySchedule` mapping exists in both the service (~230) and the repository (:49). 4. **Duplicated Code / Middle Man.** The controller builds a `BusinessDaySchedule(source="MANUAL", recorded=True)` (`occupancy_controller.py:277`), and the service builds the same object again (`occupancy_service.py:367`). Pass only the corrected fields. 5. **Shotgun Surgery.** Four controllers repeat "freeze today before a schedule edit" (`occupancy_controller.py:132,190,333,358`). Move it next to the writes in the service, so a new edit route can't skip it. 6. **Primitive Obsession.** The source list is defined three times: `ScheduleSource` (`facility_time.py:49`), `ScheduleSourceValue` (`occupancy_models.py:324`) and the DB CHECK. Keep one source of truth. 7. **Performance.** Every call to `get_active_schedule_info_async` runs `ensure_*` and then loads the full calendar, including every record. Loops call it once per cycle (`analytics_service.py:929,1038`, `occupancy_service.py:1467`), and on every event (`:717`), so the cost grows with history. The monitor also reads the reset time on every 1 s tick (`monitor_service.py:~98`). 8. **Missing annotation.** `last_schedule_day = None` in `monitor_service.py` should be annotated `date | None`. 9. **Hardcoded Spanish.** `"Excepción de horario"` and the Spanish `day_names` moved into the service (`occupancy_service.py:226,391`) unchanged. This predates the PR and overlaps #73 and #184. 10. **Missing test.** No test checks that a non-admin gets 403 on the stamp, correct or audit routes. ## Spec **Checked and correct:** - The monitor freezes the day on its first loop and on every business-day change (`monitor_service.py:103-108`). - Business days go through `facility_cycle_bounds`, so an edit between 00:00 and the reset freezes the previous day. - The weekly, exception and config endpoints freeze the current day before they write. - No code path resolves a day's schedule outside `schedule_for`. - Overwrite requires a range plus confirmation. Corrections are limited to past days. - Audit rows hold actor, reason, and old and new values. - The UI uses the Schedule Exception wording and warns that changing the reset time re-cuts history. **P2** 11. **(a) The default stamp skips days with no counts.** Spec: *"by default fills only days that have no record"* and *"records can exist for any date, not only days with counted data"*. With no dates given, the service keeps only `has_data` days (`occupancy_service.py:326`). Closed and outage days with zero counts stay unrecorded, so a later weekly edit reclassifies them. That breaks *"Editing the weekly schedule … never changes a … past day's classification"*. Default to the full span, including days with no data. 12. **(a) The one-reader test never touches statistics.** Spec: *"one-reader consistency (statistics and live view agree for the same day)"*. The test compares `ScheduleCalendar` with `get_active_schedule_info_async` only. Add an assertion through an `analytics_service` path: the Closed Day list (`analytics_service.py:439/811`), or dwell and dayparts (`:929/1038`). **P3** 13. **(a) Automatic freezes are not audit-logged.** Spec: *"every stamp or correction is audit-logged"*. `ensure_business_day_schedule_record_async` (`occupancy_repository.py:~838`) writes no audit row. After a restart that spans the reset, the day is recorded late with the plan in force at that moment, and nothing shows it was late. Add an audit row with actor `system`, or a recorded-at timestamp that shows the lateness. 14. **(c) A correction can still reach calibration.** Spec: *"a correction never re-runs an audit or feeds old data into the current calibration"*. The completed-cycle audit reads the reader (`occupancy_service.py:1214`). If an admin corrects yesterday before the auto-audit runs, the corrected hours feed k. Pin the audit to the hours recorded at freeze time, or document this window. 15. **(b) Scope creep, reasonable.** The PR adds a `GET /schedule/days/{d}` route, an `/audit` route, a 10-year cap on stamp ranges, and `schedule_source` / `schedule_recorded` fields in the live info. The API docs count jumps from 66 to 80. The old 66 was stale, and only 4 routes are new. **Summary** - **Standards:** 2 P2s, 8 P3s. The worst is the ES "días cerrados" clash with the Closed Day term. - **Spec:** 2 P2s, 3 P3s. The worst is that the default stamp skips zero-count days, which a later weekly edit can reclassify. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(schedule): address first review findings
All checks were successful
CI / lint-and-test (pull_request) Successful in 2m35s
69ba31a326
Author
Owner

First review pass addressed

All 4 P2 findings and the actionable P3 findings from the first pass are addressed in the follow-up commit.

  • Corrected the Spanish completed-day wording and made correction labels uppercase with a singular schedule-exception label.
  • Default stamping now fills every completed day between the first and last counted event, including zero-count days; existing records remain untouched unless an explicit range is confirmed for overwrite.
  • Added a statistics service assertion alongside the live reader test, plus tests for automatic freeze auditing, calibration's original schedule, service-owned freeze-before-edit, and non-admin 403 responses.
  • Consolidated source values, record decoding, and upsert SQL. Schedule edits now go through service methods, and the controller passes correction fields directly.
  • Live reads fetch one day's record; the monitor reads reset configuration at the next boundary or every 60 seconds. The monitor day variable is annotated.
  • Automatic freezes write an atomic FREEZE audit row with actor system and timestamp. Calibration uses the first schedule value recorded for a day, so later corrections change statistics without teaching the completed-cycle audit.
  • Replaced the new service's hardcoded Spanish weekday and exception fallbacks with stored names or neutral date labels.

The review's scope observation (#15) was advisory; the extra read/audit routes and stamp range cap remain documented and scoped to #113.

Ruff, formatting, JavaScript syntax, documentation checks, and the focused tests pass. The commit hook also reran the full pytest suite.

Please run the second review pass against this updated branch.

## First review pass addressed All 4 P2 findings and the actionable P3 findings from the first pass are addressed in the follow-up commit. - Corrected the Spanish completed-day wording and made correction labels uppercase with a singular schedule-exception label. - Default stamping now fills every completed day between the first and last counted event, including zero-count days; existing records remain untouched unless an explicit range is confirmed for overwrite. - Added a statistics service assertion alongside the live reader test, plus tests for automatic freeze auditing, calibration's original schedule, service-owned freeze-before-edit, and non-admin 403 responses. - Consolidated source values, record decoding, and upsert SQL. Schedule edits now go through service methods, and the controller passes correction fields directly. - Live reads fetch one day's record; the monitor reads reset configuration at the next boundary or every 60 seconds. The monitor day variable is annotated. - Automatic freezes write an atomic `FREEZE` audit row with actor `system` and timestamp. Calibration uses the first schedule value recorded for a day, so later corrections change statistics without teaching the completed-cycle audit. - Replaced the new service's hardcoded Spanish weekday and exception fallbacks with stored names or neutral date labels. The review's scope observation (#15) was advisory; the extra read/audit routes and stamp range cap remain documented and scoped to #113. Ruff, formatting, JavaScript syntax, documentation checks, and the focused tests pass. The commit hook also reran the full pytest suite. Please run the second review pass against this updated branch.
Author
Owner

Code review, pass 2 (origin/master...69ba31a, spec #113)

Result: no P1 or P2 findings. All pass-1 findings are fixed, except #6, which is partly fixed. The 8 P3s (5 Standards, 3 Spec) are deferred to #186, following docs/standards/git-and-workflow.md ("Second pass, ordinary PR").

Verification: ruff is clean. pytest: 460 passed. Frontend tests: 242 passed. tests/test_business_day_schedules.py: 8/8 passed. CI passed on 69ba31a, and the branch is based on current master (4029c79).

Standards

Pass-1 findings

  1. ES "días completados": fixed (i18n.js:170).
  2. Uppercase labels and the singular scheduleExceptionSingular key in EN and ES: fixed.
  3. The duplication: fixed. The code uses active_business_day, a single upsert SQL constant, and BusinessDaySchedule.from_record.
  4. The controller passes payload, and the service builds the MANUAL record: fixed.
  5. Freeze-before-edit now happens in the service, and the controllers no longer take repo: fixed.
  6. Partly fixed. ScheduleSource now generates its CHECK, but the audit action list is still written twice (#186 item 1).
  7. Mostly fixed.
    • Live reads fetch one day only.
    • The analytics loops still make about 4 queries per cycle, but that cost no longer grows with history.
    • The monitor re-reads the reset time at the boundary or every 60 s. A reset-time edit still takes effect right away, because the service freezes the day when the reset time changes.
  8. The monitor's day variable is annotated: fixed.
  9. The hardcoded Spanish fallback is gone. It uses the stored day_name or the ISO date: fixed.
  10. Tests check 403 for non-admins on the audit, stamp and correct routes: fixed.

The freeze write is atomic (BEGIN IMMEDIATE). There is no new SQL outside the repositories, and the tests don't mock production state.

New findings (P3, all in #186)

  • A database whose audit table predates FREEZE, such as the local validation copy, would reject automatic freezes. Prod is safe because the table is new there.
  • get_original_business_day_schedule_async decodes the original fallback through from_record, which forces recorded=True.
  • The CHECK constraints are built with f-strings (database.py:344-351), a pattern others may copy.
  • Three new service methods have no docstring.

Spec

Pass-1 findings

  • 11: Fixed, with a gap. The default stamp now covers zero-count days between the first and last counted event. Days after the last counted event are still left out (N1).
  • 12: Fixed. The one-reader test now also checks get_statistics_period_quality_async(...).closed_days == 1.
  • 13: Fixed. Automatic freezes write a FREEZE audit row (actor system) only when a record was actually inserted, so stamping stays safe to press twice.
  • 14: Fixed. Calibration reads the day's first audit row (FREEZE, STAMP, or the fallback in force when a correction was made), never the correction. That satisfies "a correction never re-runs an audit or feeds old data into the current calibration".
  • 15: Advisory; unchanged.

New findings (P3, all in #186)

  • N1 (a): "records can exist for any date, not only days with counted data". The default stamp stops at the last counted day, so a closed stretch after counting stopped stays on the fallback.

  • N2 (c): the "first recorded value" depends on the order of audit rows. A future IMPORTED writer without an audit row would break it. This needs a design decision.

  • N3 (b): three small behavior changes nobody asked for:

    • the monitor re-reads the reset time only every 60 s;
    • an exception with no name shows its ISO date;
    • the live label uses the stored day_name.

    None of them breaks the working hours or the live label.

Summary

  • Standards: 9 of 10 pass-1 findings fixed; 5 P3s remain. The worst is that existing audit tables reject FREEZE.
  • Spec: all pass-1 findings resolved; 3 P3s. The worst is that the default stamp stops at the last counted day.

Merging.

🤖 Generated with Claude Code

## Code review, pass 2 (`origin/master...69ba31a`, spec #113) Result: **no P1 or P2 findings.** All pass-1 findings are fixed, except #6, which is partly fixed. The 8 P3s (5 Standards, 3 Spec) are deferred to **#186**, following docs/standards/git-and-workflow.md ("Second pass, ordinary PR"). **Verification:** ruff is clean. pytest: 460 passed. Frontend tests: 242 passed. `tests/test_business_day_schedules.py`: 8/8 passed. CI passed on `69ba31a`, and the branch is based on current master (4029c79). ## Standards **Pass-1 findings** 1. ES "días completados": **fixed** (`i18n.js:170`). 2. Uppercase labels and the singular `scheduleExceptionSingular` key in EN and ES: **fixed**. 3. The duplication: **fixed**. The code uses `active_business_day`, a single upsert SQL constant, and `BusinessDaySchedule.from_record`. 4. The controller passes `payload`, and the service builds the MANUAL record: **fixed**. 5. Freeze-before-edit now happens in the service, and the controllers no longer take `repo`: **fixed**. 6. **Partly fixed.** `ScheduleSource` now generates its CHECK, but the audit action list is still written twice (#186 item 1). 7. **Mostly fixed.** - Live reads fetch one day only. - The analytics loops still make about 4 queries per cycle, but that cost no longer grows with history. - The monitor re-reads the reset time at the boundary or every 60 s. A reset-time edit still takes effect right away, because the service freezes the day when the reset time changes. 8. The monitor's day variable is annotated: **fixed**. 9. The hardcoded Spanish fallback is gone. It uses the stored `day_name` or the ISO date: **fixed**. 10. Tests check 403 for non-admins on the audit, stamp and correct routes: **fixed**. The freeze write is atomic (`BEGIN IMMEDIATE`). There is no new SQL outside the repositories, and the tests don't mock production state. **New findings (P3, all in #186)** - A database whose audit table predates `FREEZE`, such as the local validation copy, would reject automatic freezes. Prod is safe because the table is new there. - `get_original_business_day_schedule_async` decodes the original fallback through `from_record`, which forces `recorded=True`. - The CHECK constraints are built with f-strings (`database.py:344-351`), a pattern others may copy. - Three new service methods have no docstring. ## Spec **Pass-1 findings** - 11: **Fixed, with a gap.** The default stamp now covers zero-count days between the first and last counted event. Days after the last counted event are still left out (N1). - 12: **Fixed.** The one-reader test now also checks `get_statistics_period_quality_async(...).closed_days == 1`. - 13: **Fixed.** Automatic freezes write a `FREEZE` audit row (actor `system`) only when a record was actually inserted, so stamping stays safe to press twice. - 14: **Fixed.** Calibration reads the day's first audit row (FREEZE, STAMP, or the fallback in force when a correction was made), never the correction. That satisfies *"a correction never re-runs an audit or feeds old data into the current calibration"*. - 15: Advisory; unchanged. **New findings (P3, all in #186)** - **N1 (a):** *"records can exist for any date, not only days with counted data"*. The default stamp stops at the last counted day, so a closed stretch after counting stopped stays on the fallback. - **N2 (c):** the "first recorded value" depends on the order of audit rows. A future IMPORTED writer without an audit row would break it. This needs a design decision. - **N3 (b):** three small behavior changes nobody asked for: - the monitor re-reads the reset time only every 60 s; - an exception with no name shows its ISO date; - the live label uses the stored `day_name`. None of them breaks the working hours or the live label. **Summary** - **Standards:** 9 of 10 pass-1 findings fixed; 5 P3s remain. The worst is that existing audit tables reject `FREEZE`. - **Spec:** all pass-1 findings resolved; 3 P3s. The worst is that the default stamp stops at the last counted day. Merging. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
gabogg merged commit b864399389 into master 2026-09-29 15:45:57 +00:00
gabogg deleted branch feat/business-day-schedule-records 2026-09-29 15:45:57 +00:00
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!176
No description provided.