Skip to content

kanban: card-level due_at, woken by the dispatcher tick - #118559

Open
yoyodine-industries wants to merge 77 commits into
NousResearch:mainfrom
yoyodine-industries:feat/kanban-card-due-at
Open

yoyodine-industries wants to merge 77 commits into
NousResearch:mainfrom
yoyodine-industries:feat/kanban-card-due-at

Conversation

@yoyodine-industries

@yoyodine-industries yoyodine-industries commented Sep 21, 2026 •

Copy link
Copy Markdown

A card can now carry a wake time. due_at (epoch seconds) plus due_window_policy are task columns the dispatcher's due-card waker honours on each tick: a card whose due time has passed is woken from scheduled into ready, and a wake whose due time lands inside a reserved execution band is deferred to the close of that band instead of starting work inside it (defer / ambient policies). Waking is not spawning — an unreadable band map or a waker crash leaves the card parked and is reported through the overdue diagnostic rather than starting work in a window that forbids it.

Surfaces:

  • hermes_cli/kanban_due.py — the sweep, the band lookup and the deferral math.
  • kanban schedule / kanban block --due-at/--due-window-policy and the parser/output plumbing; the CLI echoes an armed time back as a due_note.
  • the diagnostics payload gains the overdue/blocked-due reasons, and the dashboard shows them.
  • a kanban_meta key/value row records the waker's last-tick heartbeat (one row per key, never a log).

Also in this PR, two follow-ups: the overdue-kind assertion asks the diagnostics payload instead of parsing the rendered sweep text, and a time-fenced block auto-releases through the same sweep.

Ported from fork commits 7b5545479d50, 1dc25ea03c31, c8f6661310 onto current main. Three base-drift calls, all recorded in the resolutions:

  1. the schema hunk landed where main now has no text at all (a pure insertion): the fork's kanban_meta table is kept, and the fork's CREATE INDEX IF NOT EXISTS idx_tasks_assignee_status line is dropped because main now creates that index in kanban_db_connect.py.
  2. kanban_db_connect.py keeps both sides — main's worker_started_at column and the fork's due_at/due_window_policy.
  3. kanban_db_dispatch.py keeps the fork's due_* DispatchResult fields and main's describe_suppression; the fork's hunk context also carried a row_errors field that belongs to fix(kanban): isolate per-row dispatch faults so one poison row can't end the pass #118290, so it is excluded here to keep this PR scoped to the wake time. fix(kanban): isolate per-row dispatch faults so one poison row can't end the pass #118290 touches the same dataclass, so whichever lands second needs a trivial rebase.

Evidence, base 7b3c7aef31:

  • scripts/run_tests.sh tests/hermes_cli/test_kanban_due_wake.py → 44 passed, 0 failed
  • red on base with the same test file kept and the sources reverted (new module moved aside): the due-wake tests fail, e.g. test_schedule_without_due_at_keeps_an_existing_due_time, test_window_policy_needs_a_due_time, test_unknown_window_policy_is_refused
  • python3 -m py_compile clean on every touched module

Authored with AI assistance (Hermes Agent); diff verified manually.

Related Issue

Related Issue: none

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I ran the files this change touches, not the full suite — scripts/run_tests.sh tests/hermes_cli/test_kanban_due_wake.py → 44 passed, 0 failed. The full pytest tests/ -q was not run on this host.
  • python scripts/check passes (the blocking lint and code-health checks CI runs)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features) — new tests/hermes_cli/test_kanban_due_wake.py.
  • I've tested on my platform:

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A: the PR body records no documentation update.
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A: the PR body records no cli-config.yaml.example change.
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A: the PR body records no CONTRIBUTING.md or AGENTS.md change.
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — N/A: the PR body records no cross-platform consideration.
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A: the PR body records no tool description or schema change.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Sep 21, 2026
@yoyodine-industries

Copy link
Copy Markdown
Author

pr-evergreen: this branch conflicts with main and the automated rebase could not resolve it. Please merge the current main into the branch (or rebase onto it) and push - that is the whole ask; nothing else about the change needs to move.

@yoyodine-industries

Copy link
Copy Markdown
Author

pr-evergreen status: the hermes_cli/kanban_diagnostics.py conflict reported on 2026-09-28 is CLEARED. The branch has since been merged forward with main (head is now 75a2897, 2026-10-05) and a merge simulation against current main is clean — no conflicted path remains, so the earlier 'merge the current main into the branch and push' ask is satisfied. Nothing else about the change needs to move.

Parks a card with a due time and wakes it from the dispatcher loop, so a
time-gated card needs no wake-due-cards.sh cron entry of its own.

- kanban_db: tasks.due_at / due_window_policy (epoch seconds + band policy),
  schedule_task(due_at=...), list_due_tasks(), kanban_meta KV for the waker
  heartbeat; unblock_task clears the due time and takes an extra event payload.
- kanban_due: the waker. Reads the execution-window map, defers a wake into a
  reserved band (moved to the band close, with a comment saying so) unless the
  card is armed "ambient", fails closed on a broken map, records its heartbeat.
- kanban_db_dispatch: wake phase at the top of every tick, before the lanes are
  enumerated, so a card woken here is claimed in the same tick.
- kanban_diagnostics: "overdue_scheduled" -- a parked card past its due time is
  an error, not something to notice days later; says whether the tick is dead.
- CLI/API: hermes kanban schedule --due/--window-policy/--clear-due, the due
  time in `show`/--json, and PATCH /tasks/{id} due_at.
- Dashboard: scheduled column in board order, column hint, due badge.

33 tests in tests/hermes_cli/test_kanban_due_wake.py; the kanban suites are
unchanged (identical failure set with and without the diff).

Authored with AI assistance (Hermes Agent); diff verified manually.
… block auto-release via the due sweep

Two follow-ups to the card-level `due_at` work:

- the overdue-kind assertion now asks the diagnostics payload instead of
  parsing the rendered sweep text, so a wording change in that report cannot
  make the test pass for the wrong reason (ports 1dc25ea);
- `kanban block --due-at/--due-window-policy` arms an auto-release on a
  `blocked` landing: the due-card waker unblocks the card on the first
  dispatcher pass after that time, so a time-fenced hold releases without a
  human touching it. The CLI reports the armed time back as a `due_note`, and
  upstream's newer typed-block verdict wording (`needs a human decision` vs
  `orchestration attention needed`) is preserved (ports c8f6661).

Authored with AI assistance (Hermes Agent); diff verified manually.
pr-evergreen and others added 18 commits October 11, 2026 18:46
Conflict: hermes_cli/kanban_db.py `_TASK_OPTIONAL_COLUMNS`.

This branch adds the `due_at` column to that tuple; upstream removed
`last_heartbeat_at` from the same tuple (it is already read through
`_TASK_EPOCH_COLUMNS`, so the duplicate entry was redundant). The two edits are
independent, so the resolution keeps upstream's removal AND this branch's added
column.

Fork policy: the resolved branch is pushed to the FORK branch only; nothing is
merged to fork main, which is an upstream mirror.

Agent: platform-coder
hermes_pr_update added 26 commits October 17, 2026 21:24

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants