feat(api): author feature-explanation markdown bundle (#84) - #172
Conversation
There was a problem hiding this comment.
Solid content PR. Eight grounded markdown explainer files ship as embedded resources with a clean glob in Orbit.Application.csproj, and the xUnit contract tests lock both the manifest naming scheme and frontmatter key convention. Spot-checked all numeric constants against AppConstants (MaxUserFacts=50, habit cap=10, AI messages 20/500, streak-freeze limits, overdue window=7, lookback=365), XP formula (10+streak / +100 goal) against GamificationService, and level table against LevelDefinitions — every value is verbatim accurate. No behaviour changes, no auth/API surface touched, tests are well-structured and appropriate for an embedding contract.
Add a dedicated StreakFreezeAutoActivationService BackgroundService that auto-activates a streak freeze for a Pro user who held an active streak but logged nothing on their fully-elapsed local "yesterday". - Mirrors SlipAlertSchedulerService / HabitDueDateAdvancementService: poll interval, conservative UTC pre-filter, authoritative per-user TimeZoneHelper local-yesterday guard, single SaveChanges per tick. - Pro-only (matches ActivateStreakFreezeCommand). Spends one freeze per missed day, bounded by MaxStreakFreezesAccumulated (inventory) and MaxStreakFreezesPerMonth (monthly). - Presence-based: inserting a StreakFreeze row for the missed date preserves the streak on the next on-read RecalculateAsync; no direct streak mutation. - Idempotent: new SentStreakFreezeAlert guard entity (unique UserId+FrozenDate) plus the existing StreakFreeze unique index, both re-checked before spending. - Notifies via in-app Notification + push (IPushNotificationService); localized copy via LocaleHelper, mirroring GoalDeadlineNotificationService. - EF migration AddSentStreakFreezeAlert; account reset purges the guard table; registered in ServiceCollectionExtensions and BackgroundServiceHealthCheck. Unit tests cover the eligibility predicate, local-yesterday computation, interval default, notification copy, and the guard entity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
The first commit (approved) is solid — eight grounded explainer files with accurate constants, clean embedding glob, and a tight xUnit contract test.
The second commit introduces one correctness bug in freezes.md: it describes freezes as automatic with nothing to tap, but freeze activation is fully explicit in the backend (POST /api/Gamification/streak/freeze → ActivateStreakFreezeCommand). UserStreakService reads existing freeze records but never creates them, and there is no background job that auto-applies a freeze when a day is missed. The AI will tell Pro users their streaks are protected automatically; users who don't open the AI chat after a missed day will find their streak broken and the explanation wrong.
See the inline comment on line 24 of freezes.md for a concrete replacement and a note about the follow-on sentence on line 26.
There was a problem hiding this comment.
The prior REQUEST_CHANGES finding (auto-activation of streak freezes) is still unresolved. The third commit repointed derived_from to StreakFreezeAutoActivationService.cs ProcessUserAsync, but this file does not exist in the repo — the only freeze-activation code is the explicit ActivateStreakFreezeCommand behind POST /api/Gamification/streak/freeze. The body text of freezes.md lines 24–26 still describes freezes as fully automatic, which is incorrect given the current backend. Please either (a) revert the body to describe explicit activation, or (b) land the auto-activation service before merging this doc.
…ck (#108) Aligns StreakFreezeAutoActivationService.LoadRecentCompletionsAsync with UserStreakService.LoadStreakDataAsync by filtering out soft-deleted habits when computing recent completions, so a deleted habit's log can no longer count as activity for a date and suppress the auto-freeze. Adds DB-backed tests locking the LoadRecentCompletionsAsync contract for soft-deleted and live habit logs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add eight grounded markdown explainer files (streaks, frequencies, gamification, paygate, schedule-math, freezes, notifications, ai-memory) so the in-app AI answers feature questions from code-accurate content. Each file carries a 6-key YAML frontmatter and a body whose constants are copied verbatim from AppConstants, LevelDefinitions, and the streak/schedule/paygate/reminder services. Ship the bundle inside the API binary via the first EmbeddedResource glob in the repo; resources embed as Orbit.Application.Chat.Content.FeatureExplanations.<key>.md, the documented loader contract for the downstream consumer. Refs thomasluizon/orbit-ui-mobile#84 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#108) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Rebased onto Why: the claude[bot] CHANGES_REQUESTED finding was correct. Stacking on #108 fixes it at the root rather than rewording the doc:
Rebase was conflict-free (disjoint file sets: #84 adds markdown plus an embed test; #108 adds the service / removes the manual command). Validated: |
There was a problem hiding this comment.
The prior CHANGES_REQUESTED finding (auto-activation service missing) is fully resolved: StreakFreezeAutoActivationService.cs is present on the rebased branch, ActivateStreakFreezeCommand is gone, and freezes.md's body and derived_from are accurate. Eight grounded explainer files embed cleanly via the csproj glob, all numeric constants (habit cap, AI message limits, freeze limits, overdue window, streak lookback, XP formula, level thresholds) match the backend source of truth, and the xUnit embedding contract tests (9/9) lock both manifest naming and frontmatter key convention. Solid content PR — approved.
Summary
Authors eight grounded markdown explainer files so the in-app AI can answer how Orbit features work with concrete, code-accurate content instead of guesses:
streaks.md,frequencies.md,gamification.md,paygate.md,schedule-math.md,freezes.md,notifications.md,ai-memory.mdEach file carries a 6-key YAML frontmatter (
key,display_name,related_capabilities,related_surfaces,version,derived_from) and a body whose numbers are copied verbatim from the backend source of truth (AppConstants,LevelDefinitions, and the streak / schedule / paygate / reminder services). Allrelated_capabilitiesandrelated_surfacesids are drawn from the real agent catalog (AgentCapabilityIds/AgentCatalogService.BuildSurfaces).The bundle ships inside the API binary via the repo's first
<EmbeddedResource>glob inOrbit.Application.csproj. Resources embed as:This manifest prefix is the documented loader contract for the downstream consumer (#90).
Pure content: no
.csbehavior changes (one csproj glob + the markdown bundle).Tests
Adds
FeatureExplanationResourceTests(xUnit) which locks the embedding contract: exactly the 8 expected resources are present with the documented manifest names, and each stream loads with a frontmatterkeymatching its filename stem.Validation
dotnet build src/Orbit.Application/Orbit.Application.csproj -c Release— succeeds, 0 warnings.dotnet build Orbit.slnx -c Release— succeeds, 0 errors (pre-existing warnings only).dotnet test(FeatureExplanationResourceTests) — 9 passed, 0 failed.Refs thomasluizon/orbit-ui-mobile#84