Skip to content

feat(rewards): per-user assignment with runtime entity sync — no reload#162

Merged
ccpk1 merged 2 commits into
mainfrom
ccpk1/issue77
Jun 2, 2026
Merged

feat(rewards): per-user assignment with runtime entity sync — no reload#162
ccpk1 merged 2 commits into
mainfrom
ccpk1/issue77

Conversation

@ccpk1
Copy link
Copy Markdown
Owner

@ccpk1 ccpk1 commented Jun 2, 2026

Summary

Two major feature improvements to rewards: per-user assignment with entity gating, and runtime entity sync that eliminates full integration reloads during reward configuration.

1. Per-User Reward Assignment

Rewards now support per-user assignment via the assigned_user_ids field, matching the same pattern used by chores, badges, achievements, and challenges.

  • Default behavior: All gamified users are assigned to every reward (backward compatible)
  • Options flow: Add/edit reward forms include an "Assigned to" multi-select dropdown, pre-populated with all gamified users
  • Services: create_reward and update_reward accept assigned_user_names (display names resolved to UUIDs) — use ["*"] for all users, pass an empty list to remove all assigned users
  • Entity gating: AssigneeRewardStatusSensor and reward buttons (redeem, approve, disapprove) are only created for assigned users
  • Dashboard helper: Rewards list filters by assignment — unassigned users no longer see stale entries
  • Status sensor: Exposes assigned_user_names attribute showing current assignment
  • Services bypass assignment: redeem_reward, approve_reward, and disapprove_reward work regardless of assignment — administrators can create "hidden" rewards applied via automation only

2. Runtime Entity Sync (No Reload)

Reward create and assignment updates no longer trigger a full integration reload. Targeted runtime entity sync handles sensor and button creation/removal without disrupting the active dashboard.

  • create_reward_entities(): Upgraded from test-only to production, with assignee_ids parameter for targeted creation
  • create_reward_button_entities(): New function for runtime creation of redeem, approve, and disapprove buttons
  • async_sync_reward_entities(): Coordinator entry point for one-step entity sync (create + orphan cleanup)
  • All reward CRUD paths: Services (create_reward, update_reward) and options flow (add/edit reward) use runtime sync instead of reload
  • Non-reward domains: Continue using their existing reload mechanisms — this is reward-scoped only

Validation

  • Ruff ✅, MyPy 0 errors ✅, boundary checks 13/13 ✅
  • 74 tests pass (13 new + 61 existing)
  • Manual testing confirms dashboard remains responsive during assignment changes

Closes #77
Relates to #126

ccpk1 added 2 commits June 2, 2026 16:03
Add DATA_REWARD_ASSIGNED_USER_IDS field to RewardData TypedDict.
Use SENTINEL_ALL_USERS ("*") as an input-only shortcut — resolved to
explicit gamified user UUIDs at service/flow boundaries, never
persisted. Boot normalization converts any legacy sentinel or missing
fields to explicit UUIDs. Empty lists ("no users") pass through
unchanged and are intentionally supported for blank-to-clear.

Entity gating:
- AssigneeRewardStatusSensor, AssigneeRewardRedeemButton,
  ApproverRewardApproveButton, and ApproverRewardDisapproveButton
  are only created for users assigned to the reward
- Orphaned entities are cleaned via
  remove_orphaned_assignee_reward_entities()
- Dashboard helper rewards list filters by assignment
- Reward status sensor exposes assigned_user_names attribute
  from stored UUIDs (no sentinel expansion needed)

Service layer:
- create_reward and update_reward accept assigned_user_names
  (display names resolved to UUIDs, "*" expands to all gamified)
  and assigned_user_ids (sentinel resolved same as names)
- Services bypass assignment gating by design — administrators
  can redeem/approve rewards for unassigned users via automation
- update_reward() triggers orphan entity cleanup on assignment
  changes; empty list removes all assigned users
- Options flow add/edit reward steps include multi-select for
  assigned users, pre-populated with all gamified users on create

Build/release:
- services.yaml and en.json document assigned_user_names field
  with blank-to-clear pattern and sentinel expansion
- Wiki updated: Configuration:-Rewards, Services:-Reference
- 13 new tests; 72 total pass with zero regressions

Closes #77
Reward create and assignment updates no longer trigger a full
integration reload. Instead, a targeted runtime entity sync handles
sensor and button creation without disrupting the active dashboard.

- create_reward_entities() upgraded from test-only to production,
  with assignee_ids parameter for targeted creation
- create_reward_button_entities() added to button.py for runtime
  creation of reward redeem, approve, and disapprove buttons
- async_sync_reward_entities() added to coordinator.py for
  one-step entity sync orchestration (create + cleanup)
- Services (create_reward, update_reward) and options flow
  (add/edit reward) use runtime sync instead of reload
- reward_manager.update_reward() no longer spawns async orphan
  cleanup; caller sync handles entity lifecycle
- 2 new "no reload" regression tests; 74 total pass
@ccpk1 ccpk1 added the enh: feature Feature request for new capability label Jun 2, 2026
@ccpk1 ccpk1 self-assigned this Jun 2, 2026
@ccpk1 ccpk1 added area: integration Integration logic and state enhancement New feature or request labels Jun 2, 2026
@ccpk1 ccpk1 merged commit 92dc98f into main Jun 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: integration Integration logic and state enh: feature Feature request for new capability enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REQ] Allow rewards to be locked/unlocked

1 participant