Spec-compliance review (2026-07-15): findings & gap list #40

Closed
opened 2026-07-15 15:18:16 +00:00 by claude-bot · 1 comment
Contributor

Full-project review of the v1 implementation against docs/iris-spec.md, performed 2026-07-15. Three parallel audits (backend, frontend, infra/content/docs) plus a local reproduction of every failing CI job. This issue records the findings; individual gaps should be split into their own issues (proposed breakdown at the bottom).

Release blockers (v1.0.0)

1. CI has never passed — all 52 runs red. Local reproduction of each job found concrete causes, all real code issues (not runner problems):

  • ruff check: 159 violations (60 auto-fixable); ruff format --check: 56 of 83 files unformatted
  • mypy app/: 75 errors in 17 files (callable as a type, missing generics, untyped defs)
  • pytest: collection fails outright — tests/test_ai_suggestion.py, test_webhooks.py, test_wled.py import respx, but the dev dependency group ships pytest-httpx instead. With respx installed: 201 passed, 1 failed
  • The 1 real test failure: test_import_export.py::test_builtin_yaml_covers_bundled_events opens config/events.yaml relative to cwd; CI's working dir is backend/, so it fails on any runner
  • alembic check: genuine model/migration drift — models dropped ix_sessions_expires_at, ix_sessions_subject, ix_webhook_configs_enabled with no migration
  • ESLint: one @typescript-eslint/no-empty-object-type error in frontend/src/components/ui/input.tsx:4
  • Consequence: 5 Renovate PRs (#35–#39) are blocked behind red CI

2. SESSION_SECRET never reaches the container. Three docs (setup, troubleshooting, ASVS review) instruct users to set it, but it is absent from docker-compose.yml's environment block and .env.example, and no .env is mounted/copied into the image — every compose deployment silently runs with the hardcoded default change-me-in-production, i.e. forgeable session cookies.

3. Priority/conflict resolution is not wired to pushes. services/priority_resolver.get_events_for_date correctly implements date pins, secondaries, and user-event shadowing (spec §2.5) but is referenced only by its own tests. Both real push paths (routers/wled.py push_today and schedule_service) use a naive max-priority query, so date pins and "Promote Secondary" have no runtime effect.

Spec gaps — backend

  • §4.2: per-day pre-calculated presets and HSV phase interpolation entirely absent (known: #9); generator emits one scheme per phase
  • §5.4: no-event default_scheme setting stored but never consulted — always pushes lights-off, dim_white/scheme-ref options dead
  • §5.3: retry policy retries immediately, not at 5-minute intervals; last_known_good stores state but never re-pushes on reconnect (no reconnect watcher)
  • §4.3: preset invalidation only triggers on segment changes; event phase_config/date-range edits do not stale/regenerate dependent schemes
  • §7.3: audit log misses events CRUD and date-override pin mutations ("all state-changing actions" not met); auto-regens not audited per-scheme with trigger
  • §6.1: quick-push is reverted at dim/off jobs but not at the on job
  • §12: export endpoints require admin though spec implies viewer-readable GETs

Spec gaps — frontend

  • HSV color mode absent (spec requires HSV + RGB); hex/RGB only
  • No conflict detection and no "conflicts only" filter; day-cell icon semantics deviate (✕ = rejected instead of no-scheme, ⚠ = stale instead of conflict)
  • Audit log: API client + types exist, but no page/route renders it
  • Regenerate has no confirmation modal (spec §4.3 requires warning before replacing approved presets)
  • Preview carousel only cycles the selected day's single scheme, not upcoming schemes; no stop-carousel control (API exists, unused)
  • Month backdrop is a tinted month header, not a full-width bar behind the row; day swatches are solid first-color blocks, not gradients blending color slots
  • No dismissible review-workflow guide (§10.3)
  • Settings: no static-segment color/effect editor (mode selector only), no no-event default scheme control
  • Import: raw JSON paste + single-preset association, vs spec's browsable multi-preset panel; segment mapping is a raw JSON field
  • EffectPicker hardcodes ~30 effects vs WLED's 100+
  • Quick push accepts scheme ID only, no arbitrary-color path

Content & docs

  • schemes/builtin.yaml covers ~57 keys (45 event_keys + 12 tags) vs spec §3.3's "~200 major events" — decide: expand, or amend the spec
  • World Pride Day (Jun 28) is the one §15-named event with no YAML/scheme/code reference
  • Everything else in §15 covered (via Layer 1 holidays + Layer 2 YAML); all 7 recurrence types exercised

Test coverage

  • Backend: 201 tests, good service coverage
  • Frontend: only DayCell + calendar utils unit-tested; Playwright suite is 5 loose smoke tests; no coverage of approve/reject/edit, editor, import/export, settings mutations, role gating (tracked by #5)

Code quality notes

  • invalidate_for_segment_change computes per-segment impact then unconditionally overrides it to “all schemes” (dead logic)
  • routers/auth.py callback has an unused, un-imported response: JSONResponse = None param
  • Pervasive datetime.utcnow() deprecation warnings (13k+ in a test run)
  • Recurrence tables (hindu_lunar/computed) end at 2035 — events silently vanish after
  • backend/uv.lock is untracked; committing it would make CI reproducible

Process findings

  • No milestones exist in the repo; issues are grouped only by version labels. Proposed: create v1.0.0/v1.1.0/v1.2.0/v2.0.0 milestones mirroring the labels and assign the 31 labeled issues
  • Zero issues have ever been closed — the M0–M10 history predates the tracker, but merged work (e.g. the CI migration of #2) should close its issue when acceptance criteria are met (#2's "all four jobs pass" is genuinely unmet, so it correctly remains open)

Proposed issue breakdown

  1. Fix CI: lint/format/mypy debt, respx dev-dependency, cwd-dependent test, Alembic index drift, ESLint error (blocks #5, #10, Renovate PRs)
  2. Wire SESSION_SECRET through compose/.env.example (security)
  3. Wire priority_resolver into push paths so pins/promotions take effect
  4. Implement no-event default scheme behavior
  5. Finish fallback policies (spaced retries, last-known-good re-push)
  6. Preset invalidation for event edits + audit coverage for events/pins
  7. Quick-push revert at on-job
  8. Frontend spec-parity batch (HSV, conflicts, regenerate modal, audit page, carousel, static editor, guide)
  9. Decide builtin-library scope (~57 vs ~200) + add World Pride Day
Full-project review of the v1 implementation against `docs/iris-spec.md`, performed 2026-07-15. Three parallel audits (backend, frontend, infra/content/docs) plus a local reproduction of every failing CI job. This issue records the findings; individual gaps should be split into their own issues (proposed breakdown at the bottom). ## Release blockers (v1.0.0) **1. CI has never passed — all 52 runs red.** Local reproduction of each job found concrete causes, all real code issues (not runner problems): - `ruff check`: 159 violations (60 auto-fixable); `ruff format --check`: 56 of 83 files unformatted - `mypy app/`: 75 errors in 17 files (`callable` as a type, missing generics, untyped defs) - `pytest`: collection fails outright — `tests/test_ai_suggestion.py`, `test_webhooks.py`, `test_wled.py` import `respx`, but the `dev` dependency group ships `pytest-httpx` instead. With respx installed: 201 passed, 1 failed - The 1 real test failure: `test_import_export.py::test_builtin_yaml_covers_bundled_events` opens `config/events.yaml` relative to cwd; CI's working dir is `backend/`, so it fails on any runner - `alembic check`: genuine model/migration drift — models dropped `ix_sessions_expires_at`, `ix_sessions_subject`, `ix_webhook_configs_enabled` with no migration - ESLint: one `@typescript-eslint/no-empty-object-type` error in `frontend/src/components/ui/input.tsx:4` - Consequence: 5 Renovate PRs (#35–#39) are blocked behind red CI **2. `SESSION_SECRET` never reaches the container.** Three docs (setup, troubleshooting, ASVS review) instruct users to set it, but it is absent from `docker-compose.yml`'s environment block and `.env.example`, and no `.env` is mounted/copied into the image — every compose deployment silently runs with the hardcoded default `change-me-in-production`, i.e. forgeable session cookies. **3. Priority/conflict resolution is not wired to pushes.** `services/priority_resolver.get_events_for_date` correctly implements date pins, secondaries, and user-event shadowing (spec §2.5) but is referenced only by its own tests. Both real push paths (`routers/wled.py` `push_today` and `schedule_service`) use a naive max-priority query, so date pins and "Promote Secondary" have **no runtime effect**. ## Spec gaps — backend - §4.2: per-day pre-calculated presets and HSV phase interpolation entirely absent (known: #9); generator emits one scheme per phase - §5.4: no-event `default_scheme` setting stored but never consulted — always pushes lights-off, `dim_white`/scheme-ref options dead - §5.3: `retry` policy retries immediately, not at 5-minute intervals; `last_known_good` stores state but never re-pushes on reconnect (no reconnect watcher) - §4.3: preset invalidation only triggers on segment changes; event `phase_config`/date-range edits do not stale/regenerate dependent schemes - §7.3: audit log misses events CRUD and date-override pin mutations ("all state-changing actions" not met); auto-regens not audited per-scheme with trigger - §6.1: quick-push is reverted at dim/off jobs but **not** at the on job - §12: export endpoints require admin though spec implies viewer-readable GETs ## Spec gaps — frontend - HSV color mode absent (spec requires HSV + RGB); hex/RGB only - No conflict detection and no "conflicts only" filter; day-cell icon semantics deviate (✕ = rejected instead of no-scheme, ⚠ = stale instead of conflict) - Audit log: API client + types exist, but no page/route renders it - Regenerate has no confirmation modal (spec §4.3 requires warning before replacing approved presets) - Preview carousel only cycles the selected day's single scheme, not upcoming schemes; no stop-carousel control (API exists, unused) - Month backdrop is a tinted month header, not a full-width bar behind the row; day swatches are solid first-color blocks, not gradients blending color slots - No dismissible review-workflow guide (§10.3) - Settings: no static-segment color/effect editor (mode selector only), no no-event default scheme control - Import: raw JSON paste + single-preset association, vs spec's browsable multi-preset panel; segment mapping is a raw JSON field - EffectPicker hardcodes ~30 effects vs WLED's 100+ - Quick push accepts scheme ID only, no arbitrary-color path ## Content & docs - `schemes/builtin.yaml` covers ~57 keys (45 event_keys + 12 tags) vs spec §3.3's "~200 major events" — decide: expand, or amend the spec - World Pride Day (Jun 28) is the one §15-named event with no YAML/scheme/code reference - Everything else in §15 covered (via Layer 1 `holidays` + Layer 2 YAML); all 7 recurrence types exercised ## Test coverage - Backend: 201 tests, good service coverage - Frontend: only `DayCell` + calendar utils unit-tested; Playwright suite is 5 loose smoke tests; no coverage of approve/reject/edit, editor, import/export, settings mutations, role gating (tracked by #5) ## Code quality notes - `invalidate_for_segment_change` computes per-segment impact then unconditionally overrides it to “all schemes” (dead logic) - `routers/auth.py` callback has an unused, un-imported `response: JSONResponse = None` param - Pervasive `datetime.utcnow()` deprecation warnings (13k+ in a test run) - Recurrence tables (hindu_lunar/computed) end at 2035 — events silently vanish after - `backend/uv.lock` is untracked; committing it would make CI reproducible ## Process findings - No milestones exist in the repo; issues are grouped only by version labels. Proposed: create `v1.0.0`/`v1.1.0`/`v1.2.0`/`v2.0.0` milestones mirroring the labels and assign the 31 labeled issues - Zero issues have ever been closed — the M0–M10 history predates the tracker, but merged work (e.g. the CI migration of #2) should close its issue when acceptance criteria are met (#2's "all four jobs pass" is genuinely unmet, so it correctly remains open) ## Proposed issue breakdown 1. Fix CI: lint/format/mypy debt, respx dev-dependency, cwd-dependent test, Alembic index drift, ESLint error (blocks #5, #10, Renovate PRs) 2. Wire `SESSION_SECRET` through compose/`.env.example` (security) 3. Wire `priority_resolver` into push paths so pins/promotions take effect 4. Implement no-event default scheme behavior 5. Finish fallback policies (spaced retries, last-known-good re-push) 6. Preset invalidation for event edits + audit coverage for events/pins 7. Quick-push revert at on-job 8. Frontend spec-parity batch (HSV, conflicts, regenerate modal, audit page, carousel, static editor, guide) 9. Decide builtin-library scope (~57 vs ~200) + add World Pride Day
Author
Contributor

Review findings split into individual tracked issues (all assigned to milestones):

Spec-compliance / release work (v1.0.0):

  • #41 — CI: make the pipeline green (lint/format/mypy debt, respx dev dep, cwd-dependent test, Alembic drift, ESLint)
  • #42 — Security: plumb SESSION_SECRET into docker-compose and .env.example
  • #43 — Wire priority_resolver into push paths — date pins & Promote Secondary have no runtime effect
  • #44 — Honor the no-event default_scheme setting (off / dim_white / scheme reference)
  • #45 — Finish fallback policies: 5-minute spaced retries and last_known_good re-push on reconnect
  • #46 — Preset invalidation on event edits + audit coverage for event/pin mutations
  • #47 — Revert quick-push at the on scheduler event
  • #48 — Frontend spec parity: HSV mode, conflicts, regenerate confirm, audit-log page, carousel, static editor, guide, import panel
  • #49 — Built-in scheme library: decide scope (~57 keys vs spec's ~200) and add World Pride Day

New feature proposals (v1.1.0 / v1.2.0):

  • #50 — WLED controller auto-discovery (mDNS) and segment import from the controller
  • #51 — iCal (.ics) import / subscription for personal events
  • #52 — Morning-hours lighting window (overnight-off, on again before sunrise)
  • #53 — Sync multi-scheme days as native WLED playlists
  • #54 — Nightly variation for month-long backdrop schemes
  • #55 — Per-scheme power draw estimation and PSU budget warning

Milestones v1.0.0v2.0.0 created and all version-labeled issues assigned. Closing this issue as the record of the 2026-07-15 review; remaining work is tracked in the issues above.

Review findings split into individual tracked issues (all assigned to milestones): **Spec-compliance / release work (v1.0.0):** - #41 — CI: make the pipeline green (lint/format/mypy debt, respx dev dep, cwd-dependent test, Alembic drift, ESLint) - #42 — Security: plumb SESSION_SECRET into docker-compose and .env.example - #43 — Wire priority_resolver into push paths — date pins & Promote Secondary have no runtime effect - #44 — Honor the no-event default_scheme setting (off / dim_white / scheme reference) - #45 — Finish fallback policies: 5-minute spaced retries and last_known_good re-push on reconnect - #46 — Preset invalidation on event edits + audit coverage for event/pin mutations - #47 — Revert quick-push at the on scheduler event - #48 — Frontend spec parity: HSV mode, conflicts, regenerate confirm, audit-log page, carousel, static editor, guide, import panel - #49 — Built-in scheme library: decide scope (~57 keys vs spec's ~200) and add World Pride Day **New feature proposals (v1.1.0 / v1.2.0):** - #50 — WLED controller auto-discovery (mDNS) and segment import from the controller - #51 — iCal (.ics) import / subscription for personal events - #52 — Morning-hours lighting window (overnight-off, on again before sunrise) - #53 — Sync multi-scheme days as native WLED playlists - #54 — Nightly variation for month-long backdrop schemes - #55 — Per-scheme power draw estimation and PSU budget warning Milestones `v1.0.0`–`v2.0.0` created and all version-labeled issues assigned. Closing this issue as the record of the 2026-07-15 review; remaining work is tracked in the issues above.
Sign in to join this conversation.
No milestone
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
rbrooks/Iris-WLED#40
No description provided.