Adds consistent manual Workboard movement across CLI, slash commands, and agent tools while preserving operator authority and agent claim isolation.
Co-authored-by: Ross I4JU <ross@i4ju.ch>
* fix(workboard): resolve parent dependency status via targeted lookups, not a full-corpus scan
dependencyTargetStatus() called the fully unscoped store.list() (every card,
every board, fully materialized via entries()+readCard()) just to look up the
status of a card's own parent id(s) -- almost always exactly one. dispatch()
calls promoteDependencyReady() once per card in its board-scoped pass, so
every parented card in that pass re-paid for a full-corpus re-scan.
Confirmed via a live CDP CPU profile of a real "openclaw workboard dispatch"
call (--inspect attached to a running gateway, Profiler.start/stop scoped to
the repro, elapsed 161.8s matching a known 160s+ stall): 93.3% of the time
(142s + 8.7s of 162s) was inside native SQLite all()/prepare() bindings, all
funneling through dispatch -> promoteDependencyReady -> dependencyTargetStatus
-> list -> entries -> readCard (readCard issues 4 separate synchronous SQL
statements per card). On a corpus of ~5770 cards, this is O(parented_cards_in_pass
x corpus_size x 4_queries) -- a genuine algorithmic defect, not event-loop
starvation from a concurrent session as originally suspected for this symptom.
Replace the unscoped list()+Map lookup with targeted get(parentId) calls
(already a single indexed-row lookup used everywhere else in this file) --
O(parents.length), normally O(1), instead of O(corpus size). Behavior is
unchanged: parent?.status === "done" on the get() result is exactly what
cards.get(parentId)?.status === "done" computed from the unscoped list().
Adds a regression test asserting the underlying store's entries() is called
at most once while promoting 8 parented cards together in one dispatch pass
(would have been 9 calls before this fix -- 1 outer scoped list() + 1 inner
unscoped list() per parented card).
* fix(workboard): address review feedback on dependency-target-status fastpath
Two findings from the automated PR review, both confirmed real:
- Remove an incomplete, unrelated active-owner fast-path (listActiveOwnerIds()
in store.ts + its cross-board test in store.test.ts) that leaked into this
commit from separate, still-in-progress local work. It imported
WorkboardActiveOwnerQueryable, a type that isn't defined anywhere in this
PR's tree, breaking typecheck and the bundled-extension lint check. Not
part of the dependencyTargetStatus fix this PR is scoped to.
- Replace the comparator-free, mutating .sort() calls in the new dependency
regression test with .toSorted() plus an explicit localeCompare comparator,
per the repo's lint rules.
Re-ran locally against just these two files (the actual PR diff, review WIP
set aside): pnpm lint --threads=8, pnpm format:check, pnpm tsgo:prod, pnpm
check:test-types, pnpm run lint:extensions:bundled all pass; full workboard
extension suite 111/111 (two removed tests belonged to the unrelated
active-owner code, not this fix).
---------
Co-authored-by: ClawBox <clawbox@cayk.ca>
Move Workboard durable data into a relational SQLite database and add extension doctor migration for .28 plugin-state rows. Preserve attachment lifecycle behavior, SQLite permissions/WAL settings, and scoped plugin migration access.
Adds Workboard orchestration statuses, dependency links, idempotent child creation, dispatch, and complete/block lifecycle operations backed by the plugin SQLite keyed store.
Persists tenant, skills, workspace, schedule, runtime, retry, dispatch, and handoff metadata in card records, with claim scoping and token redaction. Surfaces the new states and metadata in the Control UI, horizontal board layout, localized strings, and Workboard docs.
Verification:
- pnpm test extensions/workboard/src/store.test.ts extensions/workboard/src/tools.test.ts extensions/workboard/src/gateway.test.ts ui/src/ui/controllers/workboard.test.ts ui/src/styles/workboard.test.ts ui/src/ui/views/workboard.test.ts -- --reporter=verbose
- pnpm ui:i18n:check
- /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main, followed by focused clean local autoreview loops for final fixes
- env -u OPENCLAW_TESTBOX pnpm check:changed
- git diff --check