<feed xmlns='http://www.w3.org/2005/Atom'>
<title>doot.git/internal/models, branch master</title>
<subtitle>doot — personal productivity web app
</subtitle>
<id>https://git.terst.org/doot.git/atom?h=master</id>
<link rel='self' href='https://git.terst.org/doot.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/'/>
<updated>2026-08-10T03:16:39+00:00</updated>
<entry>
<title>Fix widget showing tomorrow's dated tasks under today</title>
<updated>2026-08-10T03:16:39+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-08-10T03:16:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=9a3ece4fef431c2c35af239f3df6eeaa10ddeaf4'/>
<id>urn:sha1:9a3ece4fef431c2c35af239f3df6eeaa10ddeaf4</id>
<content type='text'>
Root cause: doot-native and Google Tasks due dates are always
midnight-anchored (even when a task genuinely has a due date), which trips
TimelineItem.ComputeDaySection's "midnight means no specific time" heuristic
and sets IsAllDay=true on them. TimelineItemToWidgetItem then left wi.Start
nil for any Task/GTask with IsAllDay=true, and the Android client's
undated/floating pool (DootWidget.kt's `floating` list) has zero per-day
awareness -- it just packs items forward from "now" -- so a task due
tomorrow rendered as if due today. This was previously diagnosed and
deliberately set aside (see project_doot_isallday_midnight_bug memory) with
a simpler proposed fix (gate ComputeDaySection's heuristic to Event/Meal
types); re-verifying that plan against the actual code before implementing
it surfaced a real problem with it: it would also flip IsAllDay to false for
same-day dated tasks, moving them from the web's untimed-item strip into the
hourly grid with a fabricated "12:00 AM" time label -- fixing the widget by
breaking the web's currently-correct rendering.

Actual fix: added TimelineItem.Undated, a signal genuinely independent of
IsAllDay -- true only for the caller's two genuinely-dateless constructions
(nativeUndated tasks, gtasks with no due date), both of which already use
Time=now as a layout placeholder rather than a real date. ComputeDaySection
and IsAllDay are untouched, so web rendering is unaffected. This gate.go
change routes on that new signal instead: dated Task/GTask items now get
wi.Start populated (so the Android client's existing, already-correct
Start-based day bucketing runs for them) while genuinely undated ones keep
today's nil-Start floating treatment exactly as before.

Also fixed the same latent bug in wi.DueDate's guard while in the same
code path: it only checked !Time.IsZero(), but nativeUndated's Time=now
placeholder is non-zero, so an undated task's Android detail popup would
have shown a fabricated due date of whatever moment the request happened
to run. Now guards on !Undated too.

Verified: added TestTimelineItemToWidgetItem_DatedGTaskGetsStart and
TestTimelineItemToWidgetItem_UndatedTaskWithPlaceholderTime_NilDueDate,
and updated the three existing tests that had encoded the bug's old
"Start stays nil for any IsAllDay task" assumption as expected behavior
(TestTimelineItemToWidgetItem_Task, _DootTaskGetsDueDate,
_AllDayTask_KeepsFloatingBehavior -- the last one needed Undated: true
added since it no longer implies undated on its own). Proved the fix by
reverting internal/handlers/widget.go to the pre-fix condition against a
real backup and confirming exactly the three tests exercising the new
behavior fail, then restored from that backup and confirmed byte-identical.
go build/vet/test all clean.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
</content>
</entry>
<entry>
<title>Remove the feature toggle system (dead code)</title>
<updated>2026-08-06T18:19:27+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-08-06T18:19:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=06450fe69ade2928deb9274bb67b7ba60d394b4f'/>
<id>urn:sha1:06450fe69ade2928deb9274bb67b7ba60d394b4f</id>
<content type='text'>
Audited it (couldn't query the live DB directly -- auto-mode classifier
blocks direct production reads without prior approval -- so this is a
code-only audit): GetFeatureToggles/SetFeatureEnabled/IsFeatureEnabled/
CreateFeatureToggle/DeleteFeatureToggle had exactly one caller each, all
inside their own CRUD handlers. Nothing anywhere else in the codebase
read a toggle's Enabled state to gate any actual behavior -- confirmed
by grepping every remaining .Enabled/IsFeatureEnabled reference back to
either this dead code or its own tests. It was pure UI-managed CRUD with
no consumer, unlike Trusted Agents (wired into agent.go/websocket.go)
or Data Sources (wired into the sync pipeline) which stayed.

Removes the Settings page section, the three /settings/features* routes
and handlers, the five Store methods, the FeatureToggle model, and adds
028_drop_feature_toggles.sql (next free migration number, per this
repo's convention of never renumbering -- see 021_drop_tasks.sql for
the same drop-table-forward pattern) to drop the now-unused table.
Also removed the now-dead tests for all of the above.

go build ./... and go test ./... both clean.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
</content>
</entry>
<entry>
<title>fix: undated tasks were landing in the widget's scheduled-events grid</title>
<updated>2026-07-25T20:09:42+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-25T20:09:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=7f8cd6bfb894385b9ae310fd000cb921fef71cea'/>
<id>urn:sha1:7f8cd6bfb894385b9ae310fd000cb921fef71cea</id>
<content type='text'>
ComputeDaySection unconditionally recomputed IsAllDay from a
midnight-time heuristic, clobbering the IsAllDay:true flag callers set
to mark floating (no-due-date) tasks -- since undated tasks use Time =
now, this silently reset IsAllDay to false and gave them a real Start,
so the widget could render them via EventBlock/HourRow instead of
TaskRow. Their click handler always opens the calendar/source URL, so
tapping a no-due-date task (e.g. a Google Task) opened Google Calendar
instead of the task detail sheet.

ComputeDaySection now only ever sets IsAllDay true, never clears an
already-true value. Also flag IsAllDay for undated Google Tasks, which
never got it set at all (only native undated doot tasks did).
</content>
</entry>
<entry>
<title>Add bucket CRUD and read-only Projects/Labels to Settings page</title>
<updated>2026-07-18T09:38:26+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-18T09:38:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=92909ebed5df68908f32c899de1e480f8d7fb01f'/>
<id>urn:sha1:92909ebed5df68908f32c899de1e480f8d7fb01f</id>
<content type='text'>
New "Maintenance Buckets" section: create a bucket, add a pool item by
title (creates the task and assigns it in one step), remove an item,
delete a bucket (unbuckets its tasks rather than deleting them).

New read-only Projects and Labels sections (name + color swatch) --
both are simple enough that read-only is the right call on web, per
user direction, rather than duplicating the Android popup's editing
UX.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
</content>
</entry>
<entry>
<title>Rework Tasks tab: Chains section, checklist modal, project visibility</title>
<updated>2026-07-18T00:14:45+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-18T00:14:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=f08f06bef47aac2c9effb4cec650d99c2deb2dd7'/>
<id>urn:sha1:f08f06bef47aac2c9effb4cec650d99c2deb2dd7</id>
<content type='text'>
The flat Tasks-tab atom list was silently dumping every chain step
(locked and unlocked) and dormant bucket-pool items in as ordinary
undated cards, with no chain/project context and no protection against
completing a locked step out of order.

- CompleteNativeTask now rejects completing a locked chain task
  (ErrChainTaskLocked), mapped to 400 in both the widget and web
  complete-atom handlers.
- Chain tasks and dormant bucket items are excluded from the flat atom
  list; a new "Chains" section shows one card per active/paused chain
  with the current step and N/M progress.
- New chain checklist modal (GET /chains/{id}) lists every position in
  order with pause/resume/abandon -- the web view originally deferred
  as Android-only.
- Fixed a real bug this surfaced: resuming a paused chain only flipped
  the status flag, never unlocking the deferred successor, so a chain
  paused right after a completion stayed stuck forever. SetChainStatus
  now catches up the deferred advancement on resume, idempotently.
- Atom cards gained a project-name chip for general visibility.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
</content>
</entry>
<entry>
<title>Extend chain creation to accept per-task description and priority</title>
<updated>2026-07-17T22:46:18+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-17T22:46:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=be4d606e9a1f5b068abcc21bbac58d1e4705ea1f'/>
<id>urn:sha1:be4d606e9a1f5b068abcc21bbac58d1e4705ea1f</id>
<content type='text'>
CreateChain and POST /api/widget/chains previously only took bare
title strings, with priority hardcoded to 1 -- narrower than the
spec's "an ordered list of task titles/descriptions" API line. Now
accepts []models.ChainTaskInput{Content, Description, Priority} per
position, priority defaulting to 1 when omitted.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
</content>
</entry>
<entry>
<title>Implement linear task chains and recurring maintenance buckets</title>
<updated>2026-07-17T22:22:37+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-17T22:22:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=b007fee8fb5b39a5f9b369c59af71ac9e795ceaf'/>
<id>urn:sha1:b007fee8fb5b39a5f9b369c59af71ac9e795ceaf</id>
<content type='text'>
Backend, web timeline, and Android widget wiring for the last two
unimplemented items from doot-future-task-scheduling-ideas.

Chains: task_chains table + chain_id/chain_position/chain_unlocked on
native_tasks (migration 026), WIP-limit-1 advancement hooked into
CompleteNativeTask, locked tasks excluded from all date-based queries,
5 new /api/widget/chains* endpoints, an N/M position badge on web and
Android widget rows.

Buckets: maintenance_buckets table + bucket_id/bucket_state/
bucket_last_active_at on native_tasks (migration 027),
staleness-then-priority selection scoring, a new RunBucketCycleCheck
scheduler loop, 5 new endpoints including the distinct Defer action, a
Defer button on web and Android widget rows.

Also corrected stale "not yet approved" status headers on the two
already-shipped specs this work depended on (labels/projects, budgets/
availability) -- their headers were never updated after implementation.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
</content>
</entry>
<entry>
<title>Surface budget_status on GET /api/widget when tracked tasks exist</title>
<updated>2026-07-16T06:46:53+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-16T06:46:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=2413413b01925c7fab07768d7e405ac13c735000'/>
<id>urn:sha1:2413413b01925c7fab07768d7e405ac13c735000</id>
<content type='text'>
Wires ComputeBudgetPeriod together with availability blocks, tracked
project/label sets, calendar events, and native tasks into a new
computeBudgetStatus helper on *Handler. HandleWidgetGet now populates
WidgetResponse.BudgetStatus with today/week periods, but only when at
least one incomplete budget-tracked task exists in the rolling week
window -- otherwise the field is omitted entirely so unconfigured users
see no new UI. Errors are logged and swallowed, matching the existing
resilience pattern for this widget endpoint.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
</content>
</entry>
<entry>
<title>gofmt internal/models/types.go and budget.go</title>
<updated>2026-07-16T06:15:34+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-16T06:15:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=6b13197f479b98c323140d3e9d9998c32f9f6ac9'/>
<id>urn:sha1:6b13197f479b98c323140d3e9d9998c32f9f6ac9</id>
<content type='text'>
Fix formatting and alignment violations: align struct field tags in Task,
realign Weekday comment in AvailabilityBlock, and remove extra blank line
before CalendarEvent.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session
</content>
</entry>
<entry>
<title>Add budget/availability model types</title>
<updated>2026-07-16T06:12:36+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-16T06:12:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=4d2b192c7d7aae09d7a2b849b6fbb60cd7c0c23e'/>
<id>urn:sha1:4d2b192c7d7aae09d7a2b849b6fbb60cd7c0c23e</id>
<content type='text'>
Add EstimatedMinutes to Task, BudgetTracked to Project and LabelColor
structs. Create budget.go with AvailabilityBlock, BudgetPeriod, and
BudgetStatus types for modeling task budgets and calendar availability.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01PQaPGQVSfmKUiHXB87qRTC
</content>
</entry>
</feed>
