NexBoard Build Journal — Mon 23 Jun – Sun 29 Jun 2026

What shipped

  • Goal overdue logic redesign. Fixed two independent issues in the overdue engine: tasks using scheduled: frontmatter (not due:) were invisible to overdue detection, and parent task deadlines were calculated from the earliest undone subtask instead of the latest. Both fixes are concentrated in app/core.py.
  • Subtask auto-close confirmation. When a parent task is marked done with open subtasks, the UI now prompts rather than silently cascading or ignoring. Two-phase PATCH: the first request returns a confirmation payload with the open subtask list; the second carries the user’s decision — “Parent only” or “Close all”.
  • Focus + Momentum system — 9 components shipped together: a standalone scoring engine (core_momentum.py), a MomentumScore dashboard widget, a focus_session.py sprint manager, sprint entry points on mobile and in the PromiseScorecard widget, and five Telegram callbacks for sprint lifecycle management.
  • CoS memory path bug fixed. The email triage subprocess had been writing daily memory files to a legacy path for several weeks without error. Three lines of f-string substitution to absolute paths resolved it.
  • Email triage Pass 3. The Chief of Staff now extracts commitments from classified email threads and writes them to a new endpoint designed for automated sources — with string-to-float confidence mapping so callers don’t need to know the internal representation.

The interesting problem

The overdue date logic for parent tasks had a subtle correctness issue that was easy to miss: when a parent has multiple open subtasks, which subtask’s due date determines when the parent is overdue?

The original code used the earliest undone subtask due date. That’s wrong. If a project has three subtasks due on June 10, June 20, and June 30, using June 10 as the parent’s effective deadline marks the parent overdue on June 11 — while the other two subtasks are still actively in progress. A parent task genuinely can’t be complete until all its subtasks are done, which means the last due date is the real constraint.

The rewrite of _parent_overdue_info in app/core.py:

  • Uses the latest (not earliest) undone subtask due date as the constraint
  • Computes effective_due = max(parent_explicit_due, latest_undone_sub_due) independently — no coupled “any subtask overdue” gate
  • Excludes done subtasks from the calculation (they no longer constrain the parent)
effective_due = max(parent_explicit_due, latest_undone_sub_due)

The conceptual shift — from “earliest constraint” to “last constraint” — was the thing worth understanding before touching the code. The real-world test confirmed it: before the fix, 2 tasks showed overdue on a specific project. After, 5 did. The 3 that correctly stayed non-overdue all have open subtasks with future due dates.

Decision of the week

The momentum score uses three equally-weighted components: task velocity (this week vs. 4-week rolling average), commitment keep rate (fulfilled vs. cancelled over 14 days), and streak (consecutive active days, 2-day gap tolerance). Equal weight — 33/33/34% — rather than a tuned formula.

The alternative was to weight velocity higher since it’s the most direct output signal. But that lets a productive week of cancelled commitments still score well. Equal weighting forces each component to pull its weight and means you can’t compensate for a broken-promise problem with a high task count.

The first live score: 69 overall. Streak at 100 (11-day run). Velocity at 67. Keep rate at 40. The low keep rate is uncomfortable. That’s the point.

What surprised me

The CoS subprocess had been writing daily memory files to the wrong directory for several weeks, silently. The vault root happened to contain a Clawbrain/workspace-cos/ directory left over from the old multi-agent era. Because the subprocess ran with the vault as its working directory and no error was thrown when a relative path resolved to the old location, every memory write landed there instead. The briefing prompt was already using absolute paths and worked correctly; the triage section wasn’t, and didn’t.

I noticed because memory content from triage runs couldn’t be found in the expected location. The investigation — tracing which path was actually resolving, and why — took longer than the three-line fix.

What’s next

Email triage Pass 3 needs an overnight run to validate whether commitment extraction quality is usable or too noisy. The momentum system has one live data point; it needs a week of accumulation before the weights are worth revisiting. The sprint session flow — from Telegram offer through active session to completion logging — hasn’t had an end-to-end test yet.


Building NexBoard — a self-hosted AI Chief of Staff, built entirely with Claude Code.