Stop automatic cards in Chat on macOS and mobile
Chat no longer receives automatic goal/task/meeting-notes entries. Opening Chat, finishing a capture/meeting, changing tasks/goals, and releasing a deferral no longer insert goal/task/question/meeting-note cards. Existing automatic cards are hidden by provenance. Agent tool blocks and renderers stay available.
Producer inventory
| Producer | Entry path | Change |
|---|---|---|
| Daily goal/task opener | chat_first._daily_opener_blocks / _maybe_persist_daily_opener during materialize fetch | Deleted preparation and persistence |
| Rich/sparse cold start | _maybe_persist_cold_start -> proactive_engine -> server intent | Deleted producers |
| Sparse script continuation | kernel appendNextColdStartSequenceQuestion after an answer terminalizes | Deleted automatic continuation; user answers remain |
| Task/goal mutation judgment | action_items/goals post-commit wakes -> proactive_engine | Deleted wakes and engine |
| Capture arrival | finalizer -> persist_capture_arrival_intent | Deleted arrival write |
| Desktop meeting notes | meeting_receipt -> persist_receipt_intent, from-segments, finalized processing, deferred enrichment, repair/backfill | Retain audit receipt and notes; remove Chat intent and repair writes |
| Deferred question resurfacing | deferral outbox -> /v1/chat/deferrals -> release_due_deferrals -> materialization | Acknowledge retired outboxes without queue persistence or resurfacing |
| Proactive delivery | /v1 and /v2/chat/materialize-prompts, Swift presence/foreground/meeting coordinator, API driver, kernel materialize operations | Backend returns an empty compatible response; remove runner/driver; kernel rejects without a journal write |
| macOS proactive notification copy | FloatingControlBarWindow notification journal admission | Keep TTL-bounded context for explicit follow-ups; no Chat write or automatic answer row |
| Mobile daily-summary push | FCM -> MessageProvider.addMessage/history/cache | Suppress automatic day_summary history; notification/recap renderer remains |
| Empty-history greeting | GET /v2/messages initial_message_util fallback | History reads return an empty list and never synthesize a greeting |
meeting_notes_wiring/process_conversation prepare canonical notes and meeting context; they do not independently journal cards. Mobile has no proactive materializer: it consumes mirrored backend rows and cached/pushed messages. The old task/goal/question enum values now decode as text, so preserve the original wire kind for legacy filtering.
Deleted versus filtered
Deleted the opener/cold-start preparation, proactive engine and wake hooks, capture/meeting arrival persistence and repair, queue adapter, Swift fetch/ack/materialize driver, kernel automatic continuation, and tests asserting retired behavior. Kept released endpoint and receipt shapes, stored historical records, canonical meeting receipts, tools, and all rich renderers. No feature flags or historical-data mutation.
Filter markers: chatFirstIntentId/chatFirstIntentSource, cold-start producer/script subject, proactive_notification origin or an AI-turn notification continuity key, legacy task/goal/question kinds, and day_summary. Backend filtering runs before visible pagination; macOS filters the shared journal projection; mobile filters server history, older pages, cache, and push ingestion. Old mobile caches discarded provenance; a cache-format version causes a canonical history refresh before those rows can render. Ordinary rich-block types alone never hide a reply.
History visibility
Automatic rows do not consume the offset readers' reported-row scan budget, including automatic rows also marked reported. They are crossed in batches of at most 100 until the visible page fills or the collection ends. The released list response has no scan-continuation field, so another arbitrary automatic-row ceiling would still look like EOF to mobile; retain the existing reported-row allowance without capping automatic prefixes. Clean pages continue reading only the requested rows.
Cache-aligned history counts the same visibility predicate using a scoped projection of reported, sender, metadata, message_source, type, and content_blocks. Serialized provenance cannot be excluded by an aggregate. This adds projected document reads across the scope for the exact count, but preserves the existing 10ā17 visible-message append epochs without a migration or a new durable counter. The subsequent history read requests only that visible limit; redundant reported overfetch is removed.
The notification: continuity prefix hides AI turns only. User follow-ups and cold-start answers with sequence metadata remain visible in backend history, macOS projection, and mobile cache replay. The meeting banner's failure comment now points to saved conversations and notes, without adding a UI fallback.
Product invariants affected
- INV-CHAT-1: one canonical journal; the shared projection filters automatic provenance across surfaces without another timeline
- INV-NAV-1: retained explicit notification follow-up and Chat destinations
- INV-AGENT-*: retain owner/capability/run fences for user-requested tools and block appends
- INV-6: preserve user-turn continuity and rich resources; update the retired notification-copy rule in the component guide
Failure-Class: none
This implements David's 2026-10-04 product ruling removing automatic Chat entries, rather than a new inference or rollout flag.
Validation
Affected checks:
- Backend, from
backend/:BACKEND_PYTEST_WORKERS=4 BACKEND_UNIT_TEST_FILE_LIST=../.agent-brief/no-auto-chat-review-files.txt ./test.sh tests/unit/test_get_messages_reported_pagination.py tests/unit/test_chat_message_count.py tests/unit/test_chat_messages_pagination.py: 23 passed. The selector contains those three file paths; positional arguments alone do not narrow this runner. - Named-session history regression, from
backend/:BACKEND_PYTEST_WORKERS=4 BACKEND_UNIT_TEST_FILE_LIST=../.agent-brief/no-auto-chat-session-test-files.txt ./test.sh tests/unit/test_chat_session_app_identity.py: 6 passed, including the unchanged Clear Chat greeting test. The selector contains that one file path. Empty named-session GETs preserve app/session scoping, return[], and call neither the greeting helper nor message persistence. A search of the backend tests found no other positive GET-empty-history greeting assertion. - Flutter, from
app/:flutter test test/unit/server_message_content_blocks_test.dart: 12 passed. - Swift, from
desktop/macos/:xcrun swift build --build-tests --package-path Desktop, followed byxcrun swift test --skip-build --package-path Desktop --filter KernelTurnRecordedProjectionTests: build passed; 41 tests passed.
Dense-prefix regressions use 1,201 automatic rows before real messages for ordinary offset, app, and cache-aligned reads. Cache count tests retain session/app fences and exclude automatic/reported rows. All three platforms assert user notification continuity and cold-start answer visibility while preserving the AI notification filter.
Manual macOS E2E flows were not launched. No production endpoints, credentials, Firestore, app bundles, deployment, or CI monitoring. Clear Chat, initial-message routes, and integration messages are outside this change's follow-up scope.
Line-Count-Exception: backend/database/chat.py | 1524 -> 1549 | Filter automatic provenance before pagination while preserving user replies and rich blocks
š¤ Generated with Claude Code