Skill awards can trigger fund payouts (server skill-awarded activity + earned-skill-count provider) #874

Open
opened 2026-07-27 14:30:13 +00:00 by spikerj · 1 comment
Owner

Part of #868 (PR-7, backend).

Today AwardSkillCommandHandler writes the EarnedSkill and returns — no server UserActivity is emitted, and the registry's skill-earned action is a client breadcrumb the RewardEngine deliberately ignores (KnowledgeDomainRegistry.cs:799). So no staff rule can pay out for earning a skill.

  • Emit a server-side UserActivity (source server, domain Learning, new action skill-awarded, metadata: skillDefinitionId, tier, interestAreaId) from AwardSkillCommandHandler after the insert. Award-only — nothing on revoke.
  • Register skill-awarded in KnowledgeDomainRegistry as a trustworthy server action (kept distinct from the skill-earned breadcrumb).
  • New IRewardStateProvider key earned-skill-count (pattern: wishlist-country-count etc.) enabling threshold state conditions ("has ≥N skills / ≥N gold skills").
  • Tests: activity emitted on award; RewardEngine matches a skill-awarded rule end-to-end (completion + FundEarning donation); metadata condition on tier works.

Result: staff can create "earn a gold skill → $X toward your dream destination" rules in the existing admin → sponsorship-management → Location funds page.

Part of #868 (PR-7, backend). Today `AwardSkillCommandHandler` writes the `EarnedSkill` and returns — no server `UserActivity` is emitted, and the registry's `skill-earned` action is a client breadcrumb the RewardEngine deliberately ignores (`KnowledgeDomainRegistry.cs:799`). So no staff rule can pay out for earning a skill. - Emit a server-side `UserActivity` (source `server`, domain `Learning`, new action `skill-awarded`, metadata: `skillDefinitionId`, `tier`, `interestAreaId`) from `AwardSkillCommandHandler` after the insert. Award-only — nothing on revoke. - Register `skill-awarded` in `KnowledgeDomainRegistry` as a trustworthy server action (kept distinct from the `skill-earned` breadcrumb). - New `IRewardStateProvider` key `earned-skill-count` (pattern: `wishlist-country-count` etc.) enabling threshold state conditions ("has ≥N skills / ≥N gold skills"). - Tests: activity emitted on award; RewardEngine matches a `skill-awarded` rule end-to-end (completion + FundEarning donation); metadata condition on `tier` works. Result: staff can create "earn a gold skill → $X toward your dream destination" rules in the existing admin → sponsorship-management → Location funds page.
Author
Owner

Audited against origin/masterimplementation is complete; the required tests are not. Staying open on tests only. (The standalone PR #496 was closed unmerged; the work landed via consolidated backend PR #497.)

Landed

  • SpikerSoft.Business/Domain/Skills/SkillAwardedActivity.cs:20-41 — domain learning.skills, action skill-awarded, Source = "server", all three metadata keys (skillDefinitionId, tier, interestAreaId).
  • Emitted post-insert on both award paths: AwardSkillCommandHandler.cs:57 and CheckAutoAwardsCommandHandler.cs:116. Revoke correctly emits nothing.
  • KnowledgeDomainRegistry.cs:577new("skill-awarded", "Skill Awarded", "Learning", false), server-trustworthy, kept distinct from the client-side skill-earned breadcrumb at :820.
  • Provider IRewardStateProvider.cs:51-58 Key => "earned-skill-count", DI-registered at ServiceCollectionExtensions.cs:625.

Missing — 2 of the 3 required test items, plus provider coverage:

  1. No RewardEngine end-to-end test that a skill-awarded rule matches and produces a completion + FundEarning. git grep -rn "skill-awarded|SkillAwardedActivity" origin/master -- '*Tests*' hits only AwardSkillCommandHandlerTests.cs and CheckAutoAwardsCommandHandlerTests.cs — nothing in SpikerSoft.Business.Tests/Domain/Funds/RewardEngineMatchingTests.cs.
  2. No metadata-condition-on-tier test — git grep -rn '"tier"' origin/master -- 'SpikerSoft.Business.Tests/Domain/Funds/' returns nothing.
  3. No coverage for EarnedSkillCountProvidergit grep -rn "earned-skill-count|EarnedSkillCountProvider" origin/master -- '*Tests*' returns nothing.

Worth weighting this properly: the untested path disburses real money, and the epic's manual "rewards smoke test" is also unrecorded, so as far as the tracker shows the payout path has been verified neither in automation nor in production. I'd treat the two engine tests as blocking rather than nice-to-have.

Audited against `origin/master` — **implementation is complete; the required tests are not.** Staying open on tests only. (The standalone PR #496 was closed unmerged; the work landed via consolidated backend PR #497.) **Landed** - `SpikerSoft.Business/Domain/Skills/SkillAwardedActivity.cs:20-41` — domain `learning.skills`, action `skill-awarded`, `Source = "server"`, all three metadata keys (`skillDefinitionId`, `tier`, `interestAreaId`). - Emitted post-insert on both award paths: `AwardSkillCommandHandler.cs:57` and `CheckAutoAwardsCommandHandler.cs:116`. Revoke correctly emits nothing. - `KnowledgeDomainRegistry.cs:577` — `new("skill-awarded", "Skill Awarded", "Learning", false)`, server-trustworthy, kept distinct from the client-side `skill-earned` breadcrumb at `:820`. - Provider `IRewardStateProvider.cs:51-58` `Key => "earned-skill-count"`, DI-registered at `ServiceCollectionExtensions.cs:625`. **Missing — 2 of the 3 required test items, plus provider coverage:** 1. No RewardEngine end-to-end test that a `skill-awarded` rule matches and produces a completion + FundEarning. `git grep -rn "skill-awarded|SkillAwardedActivity" origin/master -- '*Tests*'` hits only `AwardSkillCommandHandlerTests.cs` and `CheckAutoAwardsCommandHandlerTests.cs` — nothing in `SpikerSoft.Business.Tests/Domain/Funds/RewardEngineMatchingTests.cs`. 2. No metadata-condition-on-`tier` test — `git grep -rn '"tier"' origin/master -- 'SpikerSoft.Business.Tests/Domain/Funds/'` returns nothing. 3. No coverage for `EarnedSkillCountProvider` — `git grep -rn "earned-skill-count|EarnedSkillCountProvider" origin/master -- '*Tests*'` returns nothing. Worth weighting this properly: the untested path **disburses real money**, and the epic's manual "rewards smoke test" is also unrecorded, so as far as the tracker shows the payout path has been verified neither in automation nor in production. I'd treat the two engine tests as blocking rather than nice-to-have.
Sign in to join this conversation.