Young's Mind
03 Decisions

"What do you think if we build board on cortex for tasks?"

Young, 2026-10-11. Measured before answering, because the honest answer is that the question is being asked one build too late — the thing you are proposing to prevent is already in the tree.

"What do you think if we build board on cortex for tasks?"

Young, 2026-10-11. Measured before answering, because the honest answer is that the question is being asked one build too late — the thing you are proposing to prevent is already in the tree.


The measurement that decides it

find /home/lab/.solos -path '*operation/state/*tasks.db'
  ace-tasks.db        tasks=1  attempts=0  events=4
  alpha-tasks.db      tasks=0  attempts=0  events=0
  atlas-tasks.db      tasks=0  attempts=0  events=0
  echo-tasks.db       tasks=0  attempts=0  events=0
  min-tasks.db        tasks=0  attempts=0  events=0
  mira-tasks.db       tasks=0  attempts=0  events=0
  nova-tasks.db       tasks=0  attempts=0  events=0
  sol-tasks.db        tasks=0  attempts=0  events=0
  v3-tasks.db         tasks=1  attempts=1  events=3
  + 6 more (exit-proof-stage2-*, diag-*)
  + ~12 in profiles' scratch dirs
  + ~12 in /home/lab/.hermes/worktrees/

Ten live task databases. Two of them hold real work. One of them is in a git worktree of a board task, so the same unit of work exists in a directory that is discarded when the card closes.

serve.py:71 and store.py:265 already do this deliberately — "runtime state, never committed — core/paths.py names the one home" — and then serve.py defaults to operation/state/<agent>-tasks.db. The docstring says "one home" and the code makes one per agent.

That is V2's five databases defect, rebuilt in V3, and it is the exact thing you are asking about.


So: does the board belong in cortex?

No — and the reason is the same D2 ruling that already closed this once.

Cortex already owns the CONTRACT. Measured: cortex/tasks/ holds states.yaml (9 wire / 14 local states), stuck.py (the 300 s rule), and no store at all — grep -rln 'sqlite|CREATE TABLE|class.*Store' cortex/ returns only a __pycache__ artifact. Sol wrote the rule into store.py itself:

"cortex/tasks/ holds the contract — 9 wire states, 14 local states… D2 closed that question: cortex owns the contract; the database is an implementation detail."

So the split is already decided and it is correct:

LayerOwnsContains
cortexthe contractstates, the stuck rule, the mappings. No data
operation/statethe implementationone sqlite file per worker. Data, no vocabulary

Moving the board into cortex would merge those two — and a store that can define its own states is precisely the second state machine V2 had. Don't.


But you are right that something is wrong

The problem is not the location, it is the count. Ten stores for one fleet is not "one home":

What I would do, in this order:

  1. One shared store per workspace, not per agent. operation/state/tasks.db — the default store.py already uses when path=None. The per-agent suffix in serve.py is what multiplied them; it exists so five agents can run side by side, but sqlite handles that with one file and a writer lock.
  2. Kill the <agent>-tasks.db default. Keep the flag, change the default. That is a one-line fix and it is Sol's file.
  3. .gitignore already covers operation/state/ — verified: "runtime state, never committed." So this is live-state sprawl, not committed history. Recoverable today.
  4. A store-drift probe, in the same spirit as Stage 0's detector: count the live *-tasks.db files and fail if more than one holds rows for the same task id. That is the two-databases defect made mechanical.

And on the board itself — it is already the answer

kanban.db is the board, and it is not ours to rebuild. Tam's finding is the licence for the lane: the dispatcher claims atomically and owns lifecycle truth; a worker executes and never owns it.

So the answer to your question is: the board does not go in cortex, and it does not go in operation/ either. It is the Hermes board. operation/state/ should hold ONE file, and it is a worker's notebook — not a second registry.

That is the same sentence as D2, one layer down: the store is an implementation detail, and a store per agent is a registry per agent.


Not established

  • Whether two workers genuinely need separate files. I have not tested concurrent writers on one sqlite store. store.py documents "single-writer (one executor)" as a class contract — so the per-agent suffix may have been protecting that assumption, and removing it needs a test, not a delete.
  • Whether the tasks=1 in ace-tasks.db and the one in v3-tasks.db are the same task. If they are, the duplication is live, not hypothetical. I have not joined them.
  • The worktree stores (/home/lab/.hermes/worktrees/t_b2df43f3/.solos/...) are a third copy path. Their lifetime is the card's, which means data loss is by design.

Addendum — the two stores are NOT the same task (measured, not assumed)

I joined them to check whether the duplication is live:

Storetask_idgoal
ace-tasks.dbprobe-1"say READY"
v3-tasks.dbe2e-systemd-test"Reply with exactly: SYSTEMD OK"
v3-tasks.dbe2e-unit-verify"Reply with exactly: UNIT OK"

So no single task is duplicated across two stores — the sprawl is empty databases rather than conflicting rows. That is materially better news than I expected, and it changes the urgency:

The per-agent default is a bug that has not yet bitten. Every worker happens to have written a different task, so nobody has seen a task go missing. That is the worst kind of defect to leave alone — it is one shared assignment away from silently losing work, and the test suite passes today because the collision has not happened yet.

The column list also differs between the two files (v3 has stop_requested_at in a different position and ace has events=4), which is the migration path store.py::_migrate() documents — more evidence these files were written by different builds against the same code.

Also measured: operation/state/ is already gitignored ("runtime state, never committed"), so this is live-state sprawl only. Nothing is in history, and nothing needs a rewrite — the fix is a default path and a drift probe.

Copyright © 2026