Skip to content

v2.0.3 fix: decode XML-plist recurrence rules, hide templates from someday#2

Merged
kaufmanhenry merged 2 commits into
mainfrom
fix/recurrence-xml-decode
Jun 16, 2026
Merged

v2.0.3 fix: decode XML-plist recurrence rules, hide templates from someday#2
kaufmanhenry merged 2 commits into
mainfrom
fix/recurrence-xml-decode

Conversation

@kaufmanhenry

Copy link
Copy Markdown
Owner

Summary

Two recurring-task bugs, both from the same wrong-format assumption as 2.0.2 — the code expected an older recurrence encoding that current Things no longer writes. Found while auditing a real database where someday returned 26 items (app showed ~10) and every repeat decoded as UNKNOWN.

src/lib/rrule.js — recurrence decoder rewrite. Current Things stores rt1_recurrenceRule as an XML property list (fu = NSCalendarUnit unit: 4=year, 8=month, 16=day, 256=weekday; fa = interval; of = weekday/day-of-month), not the binary-plist frequency/interval format the old heuristic sniffed for. Parse the XML so cadences decode (every week, every 2 weeks, every month, every 2 days).

src/lib/queries.js + src/commands/stats.js — stop templates leaking into Someday. Repeating-task templates are stored with start = 2 (same value as Someday); the app hides them and shows only generated instances. somedayTasks and the stats someday count now exclude rows with a recurrence rule.

src/commands/repeating.js — next-instance decoding. rt1_nextInstanceStartDate is a bit-packed calendar date, not Unix seconds. The old >= 1000000000 guard was never true for packed dates, so nextInstance was always null. Now decoded with thingsDateToIso / formatThingsShortDate.

Test Coverage

  • test/fixtures/build.js: fixture now emits real recurrence-rule XML and adds a Someday-template row (start=2, todayIndex=0, recurrence rule) that reproduces the real-DB leak.
  • test/integration/lists.test.js: someday excludes the template; repeating lists it and decodes freq/interval; nextInstance resolves to a real calendar date.
  • test/unit/rrule.test.js: decodes daily/weekly/monthly/yearly from fu, reads interval from fa, extracts weekday/day-of-month, accepts string or Buffer.

Tests: 79 → 79 passing (added recurrence + someday-exclusion regression cases).

Verification (real database)

  • someday: 26 → 10 items (templates gone, matches the app)
  • repeating: all 33 repeaters decode with cadence + next-instance date (genuinely-null next-instances stay null)

Pre-Landing Review

Self-reviewed; no SQL/trust-boundary/side-effect issues (read-only queries, no user input interpolated). No prompt files (evals skipped), no frontend (design review skipped).

Test plan

  • `npm test` — 13 suites, 79 tests pass (fixture rebuilt each run)
  • Verified `someday` + `repeating` against the live Things DB

🤖 Generated with Claude Code

kaufmanhenry and others added 2 commits June 16, 2026 13:50
Current Things writes the recurrence rule as an XML plist (fu=NSCalendarUnit,
fa=interval, of=weekday/day), not the binary-plist format the decoder sniffed
for, so every repeat read as UNKNOWN. Rewrite the decoder to parse it.

Repeating-task templates are stored with start=2 (same as Someday) but the app
hides them; somedayTasks and the stats someday count now exclude rows with a
recurrence rule so templates stop masquerading as Someday tasks.

rt1_nextInstanceStartDate is a bit-packed calendar date, not Unix seconds —
decode it with thingsDateToIso/formatThingsShortDate instead of the never-true
>= 1e9 guard.

Fixture emits real recurrence XML plus a Someday-template row; regression tests
cover the someday exclusion, frequency decode, and next-instance date.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kaufmanhenry kaufmanhenry merged commit 255be7f into main Jun 16, 2026
3 checks passed
@kaufmanhenry kaufmanhenry deleted the fix/recurrence-xml-decode branch June 16, 2026 18:00
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.

1 participant