From 4fce7a97e23e7d37526afaeacf723f063198667d Mon Sep 17 00:00:00 2001 From: Patrick Singletary Date: Sun, 6 Sep 2026 21:06:43 -0400 Subject: [PATCH] PLAN-timer: record scheduler createdAt finding (listItemView has no createdAt) --- docs/plans/archive/PLAN-timer.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/plans/archive/PLAN-timer.md b/docs/plans/archive/PLAN-timer.md index a54ded2..f010051 100644 --- a/docs/plans/archive/PLAN-timer.md +++ b/docs/plans/archive/PLAN-timer.md @@ -364,6 +364,20 @@ async function listItemsFor( return out; } +// FINDING (2026-09-07, verified against the @atproto/api 0.20.41 runtime +// lexicon): app.bsky.graph.getList returns items as listItemView { uri, +// subject } ONLY — there is NO createdAt on the view (required: +// ['uri','subject']; properties uri+subject only). The code above reads +// `item.createdAt`, which is therefore undefined → new Date(undefined) = +// NaN → `now < dueAtMs` is always false → every item looks due → +// sendMessage fires immediately, and new Date(NaN).toISOString() throws +// RangeError on the later INSERT (outside its try) → the dedupe row never +// lands → repeat DMs. The scheduler must source each listitem's createdAt +// from the listitem RECORD (com.atproto.repo.getRecord, collection +// app.bsky.graph.listitem, rkey from item.uri) or decode the TID +// timestamp. OWNER DECISION REQUIRED before S9 implementation; the code +// in this section is illustrative until then. + async function pollUser(did: string, convoId: string): Promise { const listsRes = await agent.app.bsky.graph.getLists({ actor: did, limit: 100 }); const now = Date.now(); -- 2.51.2