feat(api): humanize Astra daily summary, drop overdue plumbing - #186
Conversation
Rewrite the daily-summary prompt so it reads like a warm, perceptive close friend: lead with a specific acknowledgment of completed habits, then offer light guidance on at most one or two remaining habits -- no checklist, no guilt. Output stays 2-3 plain-text sentences in the user's language, no greeting or sign-off, no markdown or emoji. Make time wording period-robust: the message is cached for a whole part of the day, so it now uses a period label plus a rough range (e.g. "afternoon (~11am-5pm)") instead of the exact minute, reads correctly at both the start and end of the window, and bans now-relative phrasing. Per-habit timing uses absolute due-times. Orphaned helpers (ResolveTimeRelation, PeriodRank) are deleted. Drop includeOverdue end-to-end across the summary path: ISummaryService, AiSummaryService, GetDailySummaryQuery + handler, the controller query param, and both the in-app and external MCP get_daily_summary tools (the habit-list includeOverdue is untouched). Removing the query param is back-compatible: ASP.NET Core ignores unknown query strings. Bound summary length with a scoped ~200 maxOutputTokens via a new optional param on AiCompletionClient.CompleteTextAsync; no global cap and the JSON path is unchanged. The model stays gpt-4.1-mini -- no model config was changed. Closes #182 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Clean, well-scoped prompt engineering PR. The persona rewrite is fully backed by tests (persona rules, period-range time context, banned-instant-phrase guard, absolute due-time format). Dropping includeOverdue end-to-end is done correctly: the param was removed from every layer (interface, service, query, controller, both tool surfaces) and its call sites updated in lockstep, with backward compatibility preserved since ASP.NET Core ignores unknown query params. Adding maxOutputTokens as an optional tail parameter on CompleteTextAsync is additive — the three other callers are unaffected. Orphaned helpers (ResolveTimeRelation, PeriodRank) are gone without leaving dead code. Tests are passing and the test suite was updated to match the new signature throughout.
…streak (#213) The streak detail page's "longest" stat read the Pro-gated GET /api/gamification/streak, so free users always saw 0. Expose the already-stored user.LongestStreak on the ungated /api/profile endpoint. Additive and backward-compatible (new response field). - ProfileResponse gains LongestStreak. - Add GetProfileQueryHandler test; update MCP ProfileTools test ctor. Partial pull-forward of #186 (free-tier entitlement rebalance). Paired with orbit-ui-mobile fix/streak-free-tier. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing (#261) * feat(gamification): free-tier rebalance + infinite levels + recap (#186, #190) Reversible gamification_free_tier AppFeatureFlag (default off) unlocks streak/XP/level + streak-freeze auto-activation for free users. Infinite levels via 100*L^2 curve, continuous past level 10. New half_year_hero/streak_titan achievements + reserved first_cheer. GET /api/gamification/recap returns metrics-only retrospective + referral shareDeepLink, ungated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(astra): warm persona tone + soften act-immediately framing (#183) New EncouragingToneSection (Order 150) + softened CoreIdentitySection so clarify-first coexists with direct action; destructive/bulk route through existing confirmation-card gating. Reuses shipped resolve + pendingOperations infra; gpt-4.1-mini unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(social): social foundation - friendships, cheers, feed, moderation, handles (#193) 5 entities + User.Handle/SocialOptIn + migration w/ deterministic handle backfill. Endpoints (request/accept/remove/list/feed/cheer/block/report + set-handle + opt-in), SocialAccessGuard, rate limits. OpenAI moderation (fail-open on outage). FriendFeedEvent write-pipeline: streak hook (all users) + achievement hook (Pro) + keyset read. first_cheer wired; FCM pushes; export + deletion purge. Backend + shared only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(onboarding): setup-checklist flags, bulk-create tags, template-pack support (#187, #189) User onboarding-checklist completion flags (ride profile payload, auto-set from signals) + onboarding achievement hook (#189). BulkCreateHabits accepts per-item tags resolved/created by name for starter packs (#187). Migration AddOnboardingChecklistFlags. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(api): address PR #261 review — block-filter cheers, unblock validator, feed leak, period 400 (#193, #190) Resolves claude-review findings: add UnblockUserCommandValidator (HIGH); filter blocked users from GetCheersQuery both directions (HIGH); drop opted-out actors from the friend feed (MED); MaximumLength on friend-request handle/referralCode (MED); recap period set now matches the resolver via a shared IsKnownPeriod (single source of truth) + an invalid period returns 400 not 500 at the recap/retrospective endpoints (MED). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(api): #261 round-2 review — block/unblock rate limits, GetFriends validator, ordering, cheer-ownership Rate-limit block/unblock (50/24h); add GetFriendsQueryValidator (UserId NotEmpty); check target existence before BlockedUser.Create; verify a reported CheerId involves the reported user (else CheerNotFound). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Humanize the Astra daily summary and remove the now-unused
includeOverdueplumbing from the summary path.Prompt rewrite (the heart of #182)
Period-robust time wording
afternoon (~11am-5pm)) instead of the exact minute — it reads correctly at both the start and end of the window.due 14:00) or a title-based hint. Orphaned helpersResolveTimeRelationandPeriodRankare deleted.Drop
includeOverdueend-to-end (summary path only)Removed from
ISummaryService,AiSummaryService.GenerateSummaryAsync(+ the overdue gathering),GetDailySummaryQuery+ handler pass-through, the controller[FromQuery], the in-appGetDailySummaryTool, and the external MCPget_daily_summarytool inHabitTools. The habit-listincludeOverdue(ListHabits / GetHabitScheduleQuery / QueryHabitsTool) is untouched. Back-compatible: ASP.NET Core ignores unknown query params, so an old client sending?includeOverdue=truestill 200s.Scoped token cap
Added an optional
maxOutputTokensparam toAiCompletionClient.CompleteTextAsync(SDKMaxOutputTokenCount) and pass ~200 only from the summary call. No global cap; the JSON path and other callers are unchanged.Not changed (intentional)
AiSettings.cs/appsettings.jsonare untouched; the model staysgpt-4.1-mini. The feat(ai-summary): humanize Astra — warm-friend voice, done/today focus, period-robust time, stronger model #182 model-upgrade AC was intentionally dropped — the prompt rewrite carries the issue.Tests
AiSummaryServiceTests(35),GetDailySummaryQueryHandlerTests+GetDailySummaryToolTests(13) green. FullOrbit.Infrastructure.Tests(937) andOrbit.Application.Tests(1740) green.HH:mm), absolute due-time formatting, and a banned-instant-phrase guard.Cross-repo
Paired with the orbit-ui-mobile cleanup that stops sending the dead param: thomasluizon/orbit-ui-mobile#138
Closes #182
🤖 Generated with Claude Code