Skip to content

feat(api): humanize Astra daily summary, drop overdue plumbing - #186

Merged
thomasluizon merged 1 commit into
mainfrom
feature/wave2-humanize-summary
Jun 6, 2026
Merged

feat(api): humanize Astra daily summary, drop overdue plumbing#186
thomasluizon merged 1 commit into
mainfrom
feature/wave2-humanize-summary

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Jun 5, 2026

Copy link
Copy Markdown
Owner

What

Humanize the Astra daily summary and remove the now-unused includeOverdue plumbing from the summary path.

Prompt rewrite (the heart of #182)

  • Warm close-friend persona ("Astra"): notices and celebrates what's already done, stays easy about what's left, never corporate or coach-like.
  • Lead with completed habits, then offer light guidance on at most 1-2 remaining habits — no checklist, no guilt framing. If nothing is done yet, stays warm and forward-looking without implying "behind".
  • Output stays 2-3 plain-text sentences, in the user's language, no greeting/sign-off, no markdown/emoji/JSON.

Period-robust time wording

  • The summary is cached for a whole part of the day, so it now uses a period label + rough range (e.g. afternoon (~11am-5pm)) instead of the exact minute — it reads correctly at both the start and end of the window.
  • Enumerated now-relative instant-phrases ("right now", "earlier today", "upcoming later today", etc.) are explicitly banned in the rules and never seeded into the model-facing context (guard test added).
  • Per-habit timing uses absolute due-times (due 14:00) or a title-based hint. Orphaned helpers ResolveTimeRelation and PeriodRank are deleted.

Drop includeOverdue end-to-end (summary path only)

Removed from ISummaryService, AiSummaryService.GenerateSummaryAsync (+ the overdue gathering), GetDailySummaryQuery + handler pass-through, the controller [FromQuery], the in-app GetDailySummaryTool, and the external MCP get_daily_summary tool in HabitTools. The habit-list includeOverdue (ListHabits / GetHabitScheduleQuery / QueryHabitsTool) is untouched. Back-compatible: ASP.NET Core ignores unknown query params, so an old client sending ?includeOverdue=true still 200s.

Scoped token cap

Added an optional maxOutputTokens param to AiCompletionClient.CompleteTextAsync (SDK MaxOutputTokenCount) and pass ~200 only from the summary call. No global cap; the JSON path and other callers are unchanged.

Not changed (intentional)

Tests

  • Full solution builds clean (0 errors; no new source warnings).
  • AiSummaryServiceTests (35), GetDailySummaryQueryHandlerTests + GetDailySummaryToolTests (13) green. Full Orbit.Infrastructure.Tests (937) and Orbit.Application.Tests (1740) green.
  • New assertions: persona/lead-with-done rules present, period-range time context (no 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

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>

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

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.

@thomasluizon
thomasluizon merged commit f9144f4 into main Jun 6, 2026
4 checks passed
@thomasluizon
thomasluizon deleted the feature/wave2-humanize-summary branch June 6, 2026 00:48
thomasluizon added a commit that referenced this pull request Jun 22, 2026
…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>
thomasluizon added a commit that referenced this pull request Jun 27, 2026
…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>
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.

feat(ai-summary): humanize Astra — warm-friend voice, done/today focus, period-robust time, stronger model

1 participant