Skip to content

feat(api): author feature-explanation markdown bundle (#84) - #172

Merged
thomasluizon merged 6 commits into
mainfrom
issue-84
Jun 4, 2026
Merged

feat(api): author feature-explanation markdown bundle (#84)#172
thomasluizon merged 6 commits into
mainfrom
issue-84

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

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.md

Each 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). All related_capabilities and related_surfaces ids are drawn from the real agent catalog (AgentCapabilityIds / AgentCatalogService.BuildSurfaces).

The bundle ships inside the API binary via the repo's first <EmbeddedResource> glob in Orbit.Application.csproj. Resources embed as:

Orbit.Application.Chat.Content.FeatureExplanations.<key>.md

This manifest prefix is the documented loader contract for the downstream consumer (#90).

Pure content: no .cs behavior 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 frontmatter key matching 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.
  • Reflection check confirms exactly 8 embedded resources with the documented prefix.

Refs thomasluizon/orbit-ui-mobile#84

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

thomasluizon and others added 2 commits June 4, 2026 14:50
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>
Comment thread src/Orbit.Application/Chat/Content/FeatureExplanations/freezes.md

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/freezeActivateStreakFreezeCommand). 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.

Comment thread src/Orbit.Application/Chat/Content/FeatureExplanations/freezes.md

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

thomasluizon and others added 4 commits June 4, 2026 16:40
…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>
@thomasluizon
thomasluizon changed the base branch from main to issue-108 June 4, 2026 19:45
@thomasluizon

Copy link
Copy Markdown
Owner Author

Rebased onto issue-108 and retargeted the base from main to issue-108.

Why: the claude[bot] CHANGES_REQUESTED finding was correct. freezes.md documents the auto-activation model (derived_from: StreakFreezeAutoActivationService.cs ProcessUserAsync, body: "Freezes are automatic, there is nothing to tap"), but on this branch old base that service did not exist yet and the manual ActivateStreakFreezeCommand was still present, so the doc was inaccurate for that base.

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: dotnet build clean (0 errors), FeatureExplanationResourceTests green (9/9).

Merge order: #108 (issue-108, PR #179) first, then this PR.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Base automatically changed from issue-108 to main June 4, 2026 23:57
@thomasluizon
thomasluizon merged commit 8b6e98f into main Jun 4, 2026
2 checks passed
@thomasluizon
thomasluizon deleted the issue-84 branch June 4, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant