Skip to content

feat(reminder): add reminder engine core (domain + application) - #266

Open
LUPENGHAN wants to merge 4 commits into
1024XEngineer:mainfrom
LUPENGHAN:feature/reminder-engine-core
Open

feat(reminder): add reminder engine core (domain + application)#266
LUPENGHAN wants to merge 4 commits into
1024XEngineer:mainfrom
LUPENGHAN:feature/reminder-engine-core

Conversation

@LUPENGHAN

Copy link
Copy Markdown
Contributor

关联 Issue

Part of #263

依赖 #264#265(先合,这个 draft 现在的 diff 包含它们还没合的内容,合完 rebase 会瘦身)

改动

  • features/reminder/domain/**、application/LocalReminderApplication.ts + 全部端口接口(AlarmSchedulerPort/LocationMonitorPort/DeviceCapabilityPort/NotificationChannels/ReminderDeliveryPort/ReminderApplicationPort)
  • shared/time/format.ts,删除 MockClock/MockTimeListener
  • 含循环提醒推进到下一次发生时间的修复

验证

  • npx eslint . 全绿
  • npx tsc --noEmit 这个 PR 单独跑不过:旧的 Mock 实现和 createAppServices.ts 还没跟上这次端口签名变化,等后面的适配器/接线 PR 落地才会全绿——这层本身是纯逻辑,不影响运行时行为

本轮不含

  • 设备适配器、数据层、接线——见后续 PR

@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
timeflow Ready Ready Preview Aug 17, 2026 7:51am

@LUPENGHAN
LUPENGHAN force-pushed the feature/reminder-engine-core branch from 7570d6c to 4aeac3e Compare August 17, 2026 05:22
@LUPENGHAN
LUPENGHAN force-pushed the feature/reminder-engine-core branch from 4aeac3e to 17c2c62 Compare August 17, 2026 07:00
@LUPENGHAN
LUPENGHAN force-pushed the feature/reminder-engine-core branch from 17c2c62 to cdcce81 Compare August 17, 2026 07:25
LUPENGHAN added a commit to LUPENGHAN/timeflow that referenced this pull request Aug 17, 2026
Code review (PR 1024XEngineer#266): acknowledgeNativeFire() only checked the
persisted disposition_state (confirmed/pending) before proceeding,
not the in-memory activeDeliveries/deliverLocks sets. Those sets are
exactly what canDeliver() checks on the JS-driven handleTime path to
skip a schedule the native alarm already owns -- but the guard only
worked in that one direction. If handleTime was already mid-flight for
a schedule (added to activeDeliveries, not yet persisted any
disposition change) at the moment the native alarm for the same
schedule fired, acknowledgeNativeFire would fall through and the two
channels could both run -- the exact double-fire the surrounding
comment says this mechanism eliminates. Added the activeDeliveries
check as an additional early-return, matching canDeliver()'s guard.
LUPENGHAN and others added 3 commits August 18, 2026 16:18
LocalReminderApplication and its ports (AlarmSchedulerPort,
LocationMonitorPort, DeviceCapabilityPort, NotificationChannels,
ReminderDeliveryPort, ReminderApplicationPort), plus the domain layer
(reminder.ts, strengthDelivery.ts) that drives arm/fire/confirm state
transitions and recurring-schedule advancement.

Pure logic layer: no device-specific adapters yet, nothing wired into
the app. shared/time gains format.ts (used by the delivery strength
calc); MockClock/MockTimeListener are removed since nothing in this
stack still needs a fake clock once the real engine lands.
Code review (PR 1024XEngineer#266): acknowledgeNativeFire() only checked the
persisted disposition_state (confirmed/pending) before proceeding,
not the in-memory activeDeliveries/deliverLocks sets. Those sets are
exactly what canDeliver() checks on the JS-driven handleTime path to
skip a schedule the native alarm already owns -- but the guard only
worked in that one direction. If handleTime was already mid-flight for
a schedule (added to activeDeliveries, not yet persisted any
disposition change) at the moment the native alarm for the same
schedule fired, acknowledgeNativeFire would fall through and the two
channels could both run -- the exact double-fire the surrounding
comment says this mechanism eliminates. Added the activeDeliveries
check as an additional early-return, matching canDeliver()'s guard.
Two changes on top of the rebase onto upstream/main's native alarm module
(1024XEngineer#264/1024XEngineer#265):

- AlarmSchedulerPort.consumeNativeDispositions (single-phase, clears the
  native buffer on read) is now peekNativeDispositions + ackNativeDispositions
  (two-phase), matching the split 1024XEngineer#265 already made on the native side.
  hydrateNativeDispositions() now acks only after the whole batch persists
  successfully, so a mid-batch failure leaves the un-acked rows in the
  native buffer for retry instead of losing them.

- This PR's own interface changes (DeviceCapabilityPort.onAppActive,
  LocationMonitorPort.rebuild's new LocationRebuildTarget param, dropping
  MockTimeListener from shared/time) were never propagated to their
  implementers, so `npm run check` failed standalone -- expected for a
  mid-stack PR per its own description, but not acceptable for merging.
  Added the minimal implementations needed to close the gap: onAppActive
  on Native/MockDeviceCapability, MockLocationMonitor.rebuild's signature,
  and a new infrastructure/time/MockTimeListener placeholder. 1024XEngineer#269 replaces
  all of these with real adapters; this just keeps 1024XEngineer#266 green on its own.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@LUPENGHAN
LUPENGHAN force-pushed the feature/reminder-engine-core branch from e050333 to a057e5e Compare August 18, 2026 09:09
@LUPENGHAN
LUPENGHAN marked this pull request as ready for review August 18, 2026 09:10
@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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

本次审阅覆盖提醒领域模型、应用编排、原生闹钟处置补水、定位/权限端口及相关适配器变更。发现一个会阻塞冷启动的确定性问题;git diff --check 通过,但由于工作区未安装 frontend/node_modules,无法运行 TypeScript、ESLint 或测试命令。

Comment thread frontend/src/features/reminder/application/LocalReminderApplication.ts Outdated
…, add adapter tests

hydrateNativeDispositions() runs inside startInternal(), which is itself the
task currently occupying opChain. It was calling the public confirm()/snooze()
wrappers, which re-enqueue onto that same opChain -- but that chain can't
advance until startInternal() (the caller) returns, and startInternal() won't
return until those re-enqueued calls resolve. Any cold start with a
confirmed/snoozed row sitting in the native disposition buffer deadlocked
permanently. Fixed by calling confirmInternal()/snoozeInternal() directly,
since hydrateNativeDispositions() is already running as the sole active
opChain task and doesn't need to re-enqueue.

Also closes the Codecov patch-coverage gap on the adapter changes from the
previous commit: onAppActive on Native/MockDeviceCapability, and the
MockLocationMonitor/MockTimeListener mocks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Wintercom

Copy link
Copy Markdown
Collaborator

【测试覆盖 / 阻塞合并】本 PR 修改了 LocalReminderApplication 的核心启动、原生处置补水、时间/地点触发、送达和状态转换逻辑,但变更文件没有新增或修改 LocalReminderApplication 的应用层测试;只有 mock/适配器签名测试。git_rules.txt 第 24 行要求必要测试或验证,AI 生成代码尤其需要测试兜底。请补充应用层测试覆盖冷启动 peek/ack、confirmed/snoozed/fired 补水、native/JS 双通道竞争、确认/延后后的重排、stop/重启及周期提醒推进。

@Wintercom

Copy link
Copy Markdown
Collaborator

【Milestone 过程管理 / 阻塞合并】PR 使用 Part of #263,但 PR 本身没有 Milestone;关联的 #263 在 MS3。git_rules.txt 第 5–9 行要求本轮所有 Issue/交付挂入 Milestone,以便查看完成度和最终功能清单。请将 PR #266 归入 MS3,并确保依赖 #264/#265 已合并、PR 描述中的 draft diff/验证说明与当前 head 一致。

@Wintercom

Copy link
Copy Markdown
Collaborator

【P1 / 周期提醒不会推进到下一次发生时间】PR 描述声称修复了循环提醒推进,但当前 runDeliver() 在触发后只把 next_trigger_at 写成 null,后续没有计算/持久化下一次 RRULE occurrence,也没有重新注册下一次 AlarmManager 闹钟;resolveTimeTriggerAt() 对 recurring 又明确要求 runtime.next_trigger_at 非空,因此该周期提醒触发一次后就无法再次调度。请在一次确认/送达后的业务路径计算并保存下一次 occurrence(同时保持确认/重排语义),并补充至少两次周期触发的测试。

@Wintercom Wintercom left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

按照 git_rules.txt 的合并标准,本轮需要先处理以下阻塞项:

  1. PR 声称修复循环提醒推进,但当前实现触发后将 next_trigger_at 清空,没有计算并保存下一次 RRULE occurrence,也没有重新注册下一次 AlarmManager;周期提醒只能触发一次。
  2. LocalReminderApplication 核心逻辑有大量变更,却没有对应应用层测试,无法证明冷启动 peek/ack、双通道竞争、确认/延后重排、stop/重启和周期推进正确。
  3. PR 使用 Part of #263,但没有 Milestone;关联 Issue 在 MS3,过程追踪不完整。

具体问题已使用 gh 逐条评论。此前 reviewer 指出的 hydrateNativeDispositions 同一 opChain 死锁已在 ba17aa9 修复,本轮未重复评论。

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.

2 participants