Skip to content

✨ feat(commitments): due time + timezone#56

Merged
marcelsamyn merged 17 commits into
mainfrom
claude/wizardly-volhard-517543
Jun 8, 2026
Merged

✨ feat(commitments): due time + timezone#56
marcelsamyn merged 17 commits into
mainfrom
claude/wizardly-volhard-517543

Conversation

@marcelsamyn

Copy link
Copy Markdown
Owner

Summary

Adds an optional time of day + IANA timezone to commitment due dates, so a Task can be due "2026-06-10 at 17:00 in America/New_York" rather than only "2026-06-10". Fully additive and backward-compatible — date-only commitments are unaffected.

Data model (additive, no backfill):

  • The DUE_ON claim keeps pointing at the shared YYYY-MM-DD day node. The wall-clock time + zone are stored as the canonical human truth in the claim's metadata jsonb: { dueTime: "HH:mm", timeZone: "<IANA>" }.
  • A new nullable, indexed claims.object_instant (timestamptz) holds the resolved UTC instant (derived via a single instantFromLocalTime helper), enabling instant-precise querying. Migration 0018 adds the column + a partial index.

WritecreateCommitment / setCommitmentDue accept dueTime (24h HH:mm) + timeZone (validated IANA). Mutually required; a time requires a date. Responses echo dueTime/timeZone/dueAt. Supersession unchanged.

Read

  • dueTime/timeZone/dueAt surfaced on getOpenCommitments/getCandidateCommitments, listCommitments, and getCommitment (one shared readDueQualifier mapper; malformed metadata degrades to date-only, never 500s).
  • listCommitments: new dueAt sort key (nulls-last, reuses the existing keyset machinery) + dueBeforeInstant/dueAfterInstant filters (timed tasks only).
  • Digest buckets are instant-aware: a task due today at 09:00 flips from dueToday to overdue once 09:00 passes in the caller's zone; date-only tasks keep calendar-day comparison.
  • Both LLM context sections (open + candidate) render due=<date> <time> <zone> via a shared formatDue formatter.

Docs — SDK JSDoc, docs/sdk/commitments.md, CHANGELOG; version bumped to 1.17.0.

Non-goals: NL due-time inference in the ingestion extractor; an actual reminder scheduler (we persist a resolvable instant for a future/external one); a stored user-level timezone (caller-provided per write, matching the digest convention).

Design spec: docs/superpowers/specs/2026-06-07-commitment-due-time-design.md · Plan: docs/superpowers/plans/2026-06-07-commitment-due-time.md

Test plan

  • pnpm run test — 72 files / 361 tests pass (against Postgres on :5431)
  • pnpm run build:check — typecheck + structured-output schemas clean
  • pnpm run lint — clean
  • pnpm exec prettier --check . — clean
  • DST edges (spring-forward + fall-back determinism), half-hour zones, round-trip; write→store→read instant round-trip (17:00 America/New_York → object_instant 21:00Z → read back 17:00); set-time-then-clear; reschedule supersedes; date-only fallback
  • dueAt keyset pagination across the dated→null boundary; instant-range filters exclude date-only tasks; digest intraday overdue flip
  • Reviewer: confirm migration 0018 applies cleanly on a real DB (pnpm run drizzle:migrate)

Note: a pre-existing latent failure in open-commitments.test.ts (seed modeled superseded history as active) surfaced once the suite became runnable and is fixed in 9280444. CI does not run vitest, so it had gone unnoticed.

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for optional time-of-day and timezone precision on commitments (Tasks). It adds a new object_instant column and partial index to the claims table, promotes and extends timezone helpers, and introduces a shared DUE_ON metadata schema. Write paths (createCommitment, setCommitmentDue) and read paths (getOpenCommitments, listCommitments, getCommitment) are updated to handle, filter, sort, and display the new dueTime, timeZone, and dueAt fields. Additionally, the daily digest is updated to support instant-aware overdue bucketing, and comprehensive test coverage is added across all affected components. I have no feedback to provide as there are no review comments to assess.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

marcelsamyn and others added 17 commits June 8, 2026 09:27
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two seed claims represented superseded history but were inserted with
status='active', leaving a task with two active HAS_TASK_STATUS claims and
another with two active DUE_ON claims:
- "Done task used to be pending" → 'superseded' (task already done)
- "Review memo was previously due on 2026-04-27" → 'superseded' (rescheduled)

getOpenCommitments filters objectValue/dueOn before its newest-wins dedupe,
so the stale active claims leaked the done task into the open list and the
old due date into the dueBefore filter. Production supersession guarantees a
single active claim per (task, predicate); the seed now models that.

Pre-existing latent failures, surfaced once the suite became runnable
(CI does not run vitest).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Formatting-only pass over the due-time + timezone feature files (and the
spec/plan docs). No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t clock + DST test

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@marcelsamyn marcelsamyn force-pushed the claude/wizardly-volhard-517543 branch from c46c345 to d7bca89 Compare June 8, 2026 07:30
@marcelsamyn marcelsamyn merged commit e87aaf4 into main Jun 8, 2026
1 check passed
@marcelsamyn marcelsamyn deleted the claude/wizardly-volhard-517543 branch June 8, 2026 07:34
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