Skip to content

Add proactive context prompt MVP#188

Merged
dzarlax merged 5 commits into
mainfrom
codex/185-proactive-context-prompts
Jun 20, 2026
Merged

Add proactive context prompt MVP#188
dzarlax merged 5 commits into
mainfrom
codex/185-proactive-context-prompts

Conversation

@dzarlax

@dzarlax dzarlax commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a feature-flagged proactive context prompt lifecycle for low-sleep candidates
  • keep candidate detection separate from prompt usefulness policy, illness/check-in vetoes, and fatigue controls
  • add privacy-safe Telegram callbacks, future report caveats, retention pruning, and rollout plan docs

Validation

  • go test ./internal/storage ./cmd/server
  • go test ./...
  • git diff --check
  • privacy grep over touched implementation files

Closes #185

Summary by CodeRabbit

Release Notes

  • New Features

    • Users now receive context prompts after morning reports to provide additional sleep context (poor sleep, stress, travel, unknown, skip).
    • Admins can enable and configure check-in calendar SLA tracking with a start date for monitoring coverage.
    • Added localization support in English, Russian, and Serbian for context prompt features.
  • Documentation

    • Added implementation guidelines for proactive context prompts and check-in calendar SLA features.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dzarlax, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 2 minutes and 31 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bb99167a-c5d0-40de-9737-a21e9ef59bcc

📥 Commits

Reviewing files that changed from the base of the PR and between 3748547 and 4f229ff.

📒 Files selected for processing (4)
  • docs/ai-plans/2026-06-18-checkin-calendar-sla.html
  • docs/ai-plans/2026-06-20-proactive-context-prompts-mvp.html
  • internal/storage/briefing.go
  • internal/storage/context_prompt.go
📝 Walkthrough

Walkthrough

This PR implements two features: (1) a proactive context prompt MVP that detects low-sleep anomalies, reserves Telegram inline-keyboard prompts asking users to categorize the reason, stores answers, and renders annotations in morning reports; and (2) a subjective check-in calendar SLA that synthesizes missing/pending days after a configurable enabled_since date with a new admin POST endpoint and UI.

Changes

Proactive Context Prompts MVP

Layer / File(s) Summary
Context prompt storage: constants, types, DDL, and settings
internal/storage/context_prompt.go
Defines all exported constants (status, reason, category, source, settings keys), ContextPromptInteraction, LowSleepContextDetection, ContextAnnotation structs, the context_prompt_interactions DDL with deduplication/expiry indexes, category validation, settings accessors, and retention pruning.
Low-sleep detection, gate evaluation, and prompt reservation
internal/storage/context_prompt.go
Implements baseline computation, z-score derivation, multi-factor usefulness gate (awake hours, repeated short nights, recent equivalent prompts, illness confidence), and atomic ON CONFLICT DO NOTHING reservation.
Prompt lifecycle updates and answer persistence
internal/storage/context_prompt.go
Adds MarkContextPromptSent, MarkContextPromptSendFailed, SaveContextPromptAnswer (with FOR UPDATE transaction, expiry check, allowed-category validation, first-answer-wins), and GetContextAnnotationsForDate.
Storage unit tests
internal/storage/context_prompt_test.go
Covers DDL column assertions, category validation, avgStdDev, contextPromptCanAcceptAnswer transitions, and table-driven low-sleep detection/gate tests.
Telegram delivery module
internal/notify/context_prompt.go, internal/notify/context_prompt_test.go
Defines ContextPromptBot/ContextPromptStore interfaces, opaque inline-keyboard builder, parseContextPromptCallback, SendContextPrompt with lifecycle recording, and tests asserting opaque callback data format.
Webhook callback handling for context answers
internal/notify/checkin_callback.go, internal/notify/checkin_callback_test.go
Extends CheckinAnswerRouter with SaveContextPromptAnswer, adds early context-callback branch in NewWebhookHandler with localized ack via contextAckText, and adds TestWebhook_ContextPromptAnswer_DoesNotTriggerReport.
Briefing types, annotation fetch, and report rendering
internal/health/types.go, internal/storage/briefing.go, internal/notify/report.go, internal/notify/report_rich.go, internal/health/i18n_en.go, internal/health/i18n_ru.go, internal/health/i18n_sr.go
Adds ContextAnnotationSummary to BriefingResponse, conditionally fetches annotations in GetHealthBriefing, renders context-notes sections in plain and rich morning formats, and adds i18n strings in EN/RU/SR.
Server wiring: init, routing, send sequencing, retention
cmd/server/main.go, internal/tenants/manager.go
Ensures EnsureContextPromptInteractionsTable runs in all init paths; adds SaveContextPromptAnswer to liveCheckinRouter; refactors makeMorningTrigger/makeReportTrigger/runMorningSmartRetry to call trySendContextPromptAfterMorning after explicit mutex unlock; adds daily pruning in runDailyQualityScan.
MVP implementation plan doc
docs/ai-plans/2026-06-20-proactive-context-prompts-mvp.html
HTML doc covering MVP scope, safety/privacy boundaries, data model, prompt lifecycle, Telegram callback design, feature flags, reliability, retention, rollout metrics, and the implemented result.

Subjective Check-in Calendar SLA

Layer / File(s) Summary
CheckinCoverage SLA types and calendar synthesis
internal/storage/subjective_checkin.go, internal/storage/subjective_checkin_test.go
Adds SettingSubjectiveCheckinEnabledSince, ValidateCheckinEnabledSince/GetCheckinEnabledSince/SaveCheckinEnabledSince, Pending counter on CheckinCoverageSummary, SLA fields on CheckinCoverage, and calendarCoverageStart/buildCheckinCoverageWithSLA/checkinCoverageRow helpers; reworks GetCheckinCoverage to load enabled_since and build the SLA-augmented response.
Admin POST /api/admin/checkin-coverage handler
internal/ui/handler.go, internal/ui/admin_checkin_coverage_test.go
Extends adminCheckinCoverage to accept POST, parses a strict JSON body with enabled_since (1KB limit, DisallowUnknownFields, EOF verification), persists via SaveCheckinEnabledSince, then falls through to coverage computation; tests cover SLA activation, POST persistence, and 400 rejections.
Admin UI: SLA date input, two-table rendering, i18n, CSS
internal/ui/templates/pages/admin.html, internal/ui/style.go, internal/ui/i18n_en.go, internal/ui/i18n_ru.go, internal/ui/i18n_sr.go
Adds the checkin-enabled-since date input and save button, introduces saveCheckinEnabledSince(), refactors renderCheckinCoverage() to render separate SLA/calendar and history blocks via renderBlock(); adds .checkin-sla-settings CSS layout and checkin-status--pending pill; updates i18n in EN/RU/SR.
Check-in calendar SLA implementation plan doc
docs/ai-plans/2026-06-18-checkin-calendar-sla.html
HTML doc describing desired SLA behavior, implementation steps, test plan, QA checklist, risks/edge cases, rollback, and the implemented result.

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler
  participant DB as storage.DB
  participant TrySend as trySendContextPromptAfterMorning
  participant NotifyBot as notify.SendContextPrompt
  participant TelegramAPI

  Scheduler->>DB: MarkMorningSent (under sendMu lock)
  Scheduler->>Scheduler: sendMu.Unlock (explicit)
  Scheduler->>TrySend: signalDate, db, bot, lang
  TrySend->>DB: IsContextPromptsEnabled?
  DB-->>TrySend: true/false
  alt prompts enabled
    TrySend->>DB: ReserveLowSleepContextPrompt(signalDate, expiresAt+36h)
    DB-->>TrySend: ContextPromptInteraction or nil (conflict)
    TrySend->>NotifyBot: SendContextPrompt(bot, store, lang, prompt, now)
    NotifyBot->>TelegramAPI: SendInlineKeyboard(text, rows)
    TelegramAPI-->>NotifyBot: msgID
    NotifyBot->>DB: MarkContextPromptSent(promptID, msgID, now)
  end
Loading
sequenceDiagram
  participant TelegramWebhook
  participant WebhookHandler as NewWebhookHandler
  participant Router as liveCheckinRouter
  participant DB as storage.DB

  TelegramWebhook->>WebhookHandler: POST callback_data="ctx:cp_abc:stress"
  WebhookHandler->>WebhookHandler: parseContextPromptCallback → (promptID, category, ok)
  WebhookHandler->>Router: SaveContextPromptAnswer(promptID, category, source, now)
  Router->>DB: SaveContextPromptAnswer (FOR UPDATE tx, expiry/category check)
  DB-->>Router: (status, err)
  Router-->>WebhookHandler: status
  WebhookHandler->>TelegramAPI: AnswerCallbackQuery(contextAckText(lang, status))
  WebhookHandler-->>TelegramWebhook: HTTP 200
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • Dzarlax-AI/health_dashboard#121: Introduced the subjective daily check-in Telegram webhook flow that this PR extends with context-prompt callback parsing in internal/notify/checkin_callback.go.
  • Dzarlax-AI/health_dashboard#125: Originally introduced the /api/admin/checkin-coverage endpoint and storage shape that this PR expands with SLA fields and the POST method.
  • Dzarlax-AI/health_dashboard#137: Modified the same internal/ui/templates/pages/admin.html check-in coverage section that this PR refactors with the SLA date input and two-table rendering.

Poem

🐇 Hop, hop, the rabbit types at night,
Asking "low sleep — stress or flight?"
A calendar SLA now marks each day,
Missing, pending — nothing slips away.
Context noted, answers stored in rows,
The morning brief with annotations glows!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add proactive context prompt MVP' clearly and concisely describes the primary change—adding a feature-flagged proactive context prompt system with MVP scope, which is the main focus of this large changeset across storage, server, notification, and UI components.
Description check ✅ Passed The PR description covers the key aspects: summarizes the feature (proactive context prompts with low-sleep as first detector), lists validation steps performed (go test, git diff check, privacy review), and references the linked issue (#185). Required sections like Summary, Linked Issue, and Test Plan are present and reasonably complete.
Linked Issues check ✅ Passed The code changes comprehensively implement issue #185 requirements: feature-flagged lifecycle (detected/reserved/prompted/answered/skipped/expired/send_failed states), low-sleep detector with usefulness gating, opaque prompt IDs, privacy-safe categories (poor_sleep/stress/travel/unknown/skip), retention pruning, Telegram callback handling, and non-regression with illness-suspicion layer.
Out of Scope Changes check ✅ Passed All changes are scoped to context prompt MVP implementation (storage layer, server integration, notification/Telegram callbacks, UI admin coverage display, i18n support, and documentation). The subjective check-in SLA enhancements are foundational infrastructure for the coverage display and remain closely related to the core feature scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/185-proactive-context-prompts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3748547265

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/storage/context_prompt.go Outdated
COALESCE(category, ''), COALESCE(source, ''), COALESCE(prompt_message_id, 0),
COALESCE(prompted_at, '0001-01-01'::timestamptz), expires_at,
COALESCE(answered_at, '0001-01-01'::timestamptz), allowed_categories, metadata`,
promptID, signalDate, promptLocalDate, reason, detectorVersion, ContextPromptStatusReserved, expiresAt, allowedJSON, metadataJSON, now).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wrap context prompt JSONB values before insert

When proactive_context_prompts is enabled and a low-sleep candidate reaches this insert, allowedJSON and metadataJSON are plain []byte values from json.Marshal. With this repo's pgx setup, plain byte slices are encoded as bytea, so the $8::jsonb/$9::jsonb parameters fail the JSONB write instead of reserving the prompt; use json.RawMessage (as the other JSONB writers do) or another JSON-typed value.

Useful? React with 👍 / 👎.

Comment thread internal/storage/briefing.go Outdated
health.ApplyIllnessSafetyCap(resp, health.GetStrings(lang))

if IsContextCaveatsEnabled(s) {
if annotations, aerr := s.GetContextAnnotationsForDate(*lastDate); aerr == nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Look back for answered context caveats

Because prompts are sent only after the morning report for signalDate, the user normally answers after that report is already gone. The next morning GetHealthBriefing advances lastDate to the newer daily score, but this lookup only asks for annotations whose signal_date equals that new date, so the saved context for yesterday's low-sleep signal is never rendered in any future morning report even with context_caveats_enabled on.

Useful? React with 👍 / 👎.

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
internal/storage/context_prompt.go (1)

545-585: 💤 Low value

Remove or annotate unused timing functions.

contextSleepTimingForDate and hhmmToMinute are flagged as unused by static analysis. Since contextSleepTimingDeviation is disabled for MVP (returns false, nil), these functions are dead code. Either remove them to reduce maintenance burden, or add a // nolint:unused directive with a comment explaining they're retained for post-MVP enablement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/storage/context_prompt.go` around lines 545 - 585, The functions
contextSleepTimingForDate and hhmmToMinute are flagged as unused by static
analysis because they are only called by the disabled
contextSleepTimingDeviation function. Either remove both functions entirely to
eliminate dead code, or add a nolint:unused directive above each function
definition with a comment explaining that they are intentionally retained for
post-MVP enablement when contextSleepTimingDeviation is re-enabled.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/ai-plans/2026-06-18-checkin-calendar-sla.html`:
- Around line 204-209: The Approval Gate section containing the h2 "Approval
Gate" and paragraph about needing explicit user approval before implementation
is misleading because the document already shows an "Implemented Result" and
completed checks, indicating the work is finished. Either remove the entire
approval gate section entirely, or reword it to clearly indicate that this was a
historical approval requirement that has already been satisfied, making it clear
to future readers that the plan has been implemented and is not a current
blocker.
- Line 189: The gofmt command contains Windows-style path separators
(backslashes) in all file paths which will fail in Linux CI environments.
Replace all backslashes with forward slashes in the paths listed in the gofmt
command (internal\storage\subjective_checkin.go,
internal\storage\subjective_checkin_test.go, internal\ui\handler.go,
internal\ui\admin_checkin_coverage_test.go, internal\ui\i18n_en.go,
internal\ui\i18n_ru.go, and internal\ui\i18n_sr.go) to use POSIX-compatible
forward slashes instead.

In `@docs/ai-plans/2026-06-20-proactive-context-prompts-mvp.html`:
- Around line 135-153: Update the DDL documentation in the
context_prompt_interactions table definition to match the actual schema
implementation. First, add the NOT NULL constraint to the expires_at field
(currently shown as nullable). Second, add the DEFAULT '[]'::jsonb clause to the
allowed_categories field to match the actual implementation in
internal/storage/context_prompt.go. These two changes will align the documented
schema with what is actually implemented.
- Around line 154-157: Update the unique index definition for
context_prompt_interactions by making two corrections: first, change the index
name from `ux_context_prompt_one_sent_per_day` to
`idx_context_prompt_one_sent_per_day` to use the correct naming prefix, and
second, add `'send_failed'` to the status list in the WHERE clause alongside the
existing statuses ('reserved', 'prompted', 'answered', 'skipped', 'expired') to
match the design requirement stated elsewhere that send_failed is terminal and
part of the one-prompt-per-local-day deduplication constraint.

In `@internal/storage/context_prompt.go`:
- Around line 597-619: The JSONB parameters allowedJSON and metadataJSON are
being passed directly as []byte to the pgx query without proper wrapping. Modify
the code to wrap both allowedJSON and metadataJSON in json.RawMessage after
their respective json.Marshal calls, then pass these wrapped values to the
QueryRow call instead of the raw byte slices. This ensures proper handling of
JSONB parameters when writing via pgx v5.

---

Nitpick comments:
In `@internal/storage/context_prompt.go`:
- Around line 545-585: The functions contextSleepTimingForDate and hhmmToMinute
are flagged as unused by static analysis because they are only called by the
disabled contextSleepTimingDeviation function. Either remove both functions
entirely to eliminate dead code, or add a nolint:unused directive above each
function definition with a comment explaining that they are intentionally
retained for post-MVP enablement when contextSleepTimingDeviation is re-enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a5854ee0-47c7-4deb-93e6-619878a1f1d6

📥 Commits

Reviewing files that changed from the base of the PR and between 0b46d1e and 3748547.

📒 Files selected for processing (26)
  • cmd/server/main.go
  • docs/ai-plans/2026-06-18-checkin-calendar-sla.html
  • docs/ai-plans/2026-06-20-proactive-context-prompts-mvp.html
  • internal/health/i18n_en.go
  • internal/health/i18n_ru.go
  • internal/health/i18n_sr.go
  • internal/health/types.go
  • internal/notify/checkin_callback.go
  • internal/notify/checkin_callback_test.go
  • internal/notify/context_prompt.go
  • internal/notify/context_prompt_test.go
  • internal/notify/report.go
  • internal/notify/report_rich.go
  • internal/storage/briefing.go
  • internal/storage/context_prompt.go
  • internal/storage/context_prompt_test.go
  • internal/storage/subjective_checkin.go
  • internal/storage/subjective_checkin_test.go
  • internal/tenants/manager.go
  • internal/ui/admin_checkin_coverage_test.go
  • internal/ui/handler.go
  • internal/ui/i18n_en.go
  • internal/ui/i18n_ru.go
  • internal/ui/i18n_sr.go
  • internal/ui/style.go
  • internal/ui/templates/pages/admin.html

Comment thread docs/ai-plans/2026-06-18-checkin-calendar-sla.html Outdated
Comment thread docs/ai-plans/2026-06-18-checkin-calendar-sla.html
Comment thread docs/ai-plans/2026-06-20-proactive-context-prompts-mvp.html
Comment thread docs/ai-plans/2026-06-20-proactive-context-prompts-mvp.html Outdated
Comment thread internal/storage/context_prompt.go Outdated
dzarlax added 2 commits June 20, 2026 13:52
…ontext-prompts

# Conflicts:
#	docs/ai-plans/2026-06-18-checkin-calendar-sla.html
@dzarlax dzarlax merged commit aff4722 into main Jun 20, 2026
1 check passed
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.

Proactive context prompts for unusual personal health signals

1 participant