With tracker.descendants on, the tracker project is the root of a tree.
Each reconcile reads the sync bot's project list (archived projects and
negative pseudo-project ids left out) and walks it by parent_project_id.
A child that passes the install checks is read through its board, and
one that doesn't is watch-only (bucket 0) and never refuses the
business. A tick reads each project in the tree. A child answering 403
or 404 leaves the tree only if GET /projects/<id> then answers 403 or
404 too, and its open tasks get the one-by-one read. Task refs carry
the project, so a task moved inside the tree shows under its new ref
and the old ref gets its tombstone. tracker.descendants reaches the adapter
through the business var and packages/cli/src/config.mjs (lead decision
87). Off, the adapter reads as v0 did.
Darkwing built it (agents/darkwing/work/queue-62), in three rounds.
Round 3 was approved by Filbert (27317) and Dewey (27338) on manifest
8b81e836, 13 paths. Their non-blocking notes and Darkwing's follow-ups
(two surviving mutants in test 18, the fake's view-404 code) go to a
follow-up row.
Sage's gate on 918a4a19, sequential and teed: node suites tasks 71,
business 60, bus 80, cli 110 and queue 150, 0 failed; webui 39 of 40,
then 40 of 40 on three reruns (row 62 touches no webui file; a timing
test under load 17 with Dewey's gate running beside it); test-auth 15,
test-conductor 17, test-config 24, test-discord 66,
test-extension-package 18, test-foundation 44, test-queue 27,
test-release 14, test-task 98, all 0 failed (Docker on). edc5de71..HEAD
touches none of the 13 paths.
Live read, 2026-10-11T21:28:03Z, tasks.woltje.com v2.7.0, root #19,
descendants on, sync key only, GETs only (the startup scope probes not
sent): reconcile 15 GETs, 42 snapshots; tick 8 GETs, 0 snapshots.
Children 18, 20 and 21 are watch-only. A missing view id on #18 answers
404 (code 3014) while #18 reads 200, as the README says. Record:
agents/sage/work/vikunja-setup/2026-10-11_tick-62.json.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
93 lines
4.0 KiB
Markdown
93 lines
4.0 KiB
Markdown
# S3 live run
|
|
|
|
`run.mjs` takes one task through every verb against a real Vikunja, with
|
|
the real broker and adapter in one process. It's the row 38 acceptance
|
|
run against the estate instance, and it was rehearsed against a scratch
|
|
container first.
|
|
|
|
```sh
|
|
node packages/tasks/live/run.mjs setup.json out/ --base https://tasks.example.org
|
|
```
|
|
|
|
`--base` has to repeat `baseUrl` from the setup file, or the run exits 2
|
|
before it reads a token. A setup file copied from another install can't
|
|
send the run to the wrong host without the operator typing that host.
|
|
|
|
## Setup file
|
|
|
|
```json
|
|
{
|
|
"business": "demo",
|
|
"baseUrl": "https://tasks.example.org",
|
|
"project": 12,
|
|
"sync": {"botId": 41, "file": "/home/op/.config/mosaic-dev/tokens/demo-sync", "expires": "2027-01-01"},
|
|
"roles": {
|
|
"pm": {"botId": 42, "env": "VK_PM", "expires": "2027-01-01"},
|
|
"coder": {"botId": 43, "env": "VK_CODER", "expires": "2027-01-01"},
|
|
"reviewer": {"botId": 44, "env": "VK_REVIEWER", "expires": "2027-01-01"}
|
|
},
|
|
"labels": {"slice-1": 7}
|
|
}
|
|
```
|
|
|
|
Each token is a file or an environment variable, never a value in this
|
|
file. A token file follows the broker's rules: an absolute path, mode
|
|
0600, owned by the operator, not a symlink. `expires` is the day the
|
|
token was minted to expire, as `YYYY-MM-DD`. The project, buckets, bots
|
|
and labels come from runbook sections 2 and 3
|
|
(`docs/guides/slice-1-identities.md`). The first label in `labels` is added at create and removed at schedule.
|
|
Leave `labels` empty to skip both.
|
|
|
|
## What it does
|
|
|
|
The run builds a business with an `operator` human and the pm as arbiter
|
|
for both domains, then starts the broker with the adapter in a fresh
|
|
data directory under `TMPDIR`. The three roles claim their launches and
|
|
the adapter runs its startup checks and one reconcile.
|
|
|
|
Then the steps, in order. Each one either succeeds or refuses with the
|
|
code the step expects:
|
|
|
|
| Step | Role | Verb | Expected |
|
|
|---|---|---|---|
|
|
| create-by-coder | coder | `task.create` | `field-writer` |
|
|
| create | pm | `task.create` | ok, with the label |
|
|
| assign | pm | `task.assign` to coder | ok |
|
|
| update-by-unassigned | reviewer | `task.update.assigned` | `not-assigned` |
|
|
| start | coder | `task.update.assigned` in-progress, 25%, comment | ok |
|
|
| conflict | pm | `task.priority.change` with a wrong `expect` | `task-conflict` |
|
|
| priority-undecided | pm | `task.priority.change`, no decision | `decision-required` |
|
|
| priority | pm | `task.priority.change` with a resolved decision | ok |
|
|
| priority-reused | pm | the same decision again | `decision-consumed` |
|
|
| schedule | pm | `task.schedule` due date, label removed | ok |
|
|
| scope | pm | `task.scope.change` with a resolved decision | ok |
|
|
| review | coder | `task.update.assigned` in-review, 100% | ok |
|
|
| reassign | pm | `task.reassign` to reviewer | ok |
|
|
| close | pm | `task.close` | ok |
|
|
| after-close | reviewer | `task.update.assigned` | `task-done` |
|
|
|
|
Priority and scope are cross-role for the pm, so each needs a decision.
|
|
The pm raises it, and the operator resolves it through the broker's
|
|
human CLI binding. A tick after the start step and a tick and reconcile
|
|
at the end must each record 0 snapshots, since the only writes were the
|
|
run's own. The run then prints the event counts by kind and the snapshot
|
|
counts by source and role, read from `bus.sqlite`.
|
|
|
|
It exits 0 when every step went as expected, 1 when one didn't or the
|
|
run stopped, and 2 on a bad command line or setup file. The task stays
|
|
in the project, done, with "Safe to delete" in its description.
|
|
|
|
## Project trees
|
|
|
|
The run reads the setup's one project, with `descendants` off. It never
|
|
reads a child. A tree is checked with read-only GETs instead, listed in
|
|
`agents/darkwing/work/queue-62/probes.md`.
|
|
|
|
## The log
|
|
|
|
`out/live-run.txt`, mode 0600, holds verbs, refusal codes, counts and
|
|
task refs. It holds no token, title, description or comment. Before it
|
|
writes, the run checks the log text for every token and for the word
|
|
"bearer". A hit writes nothing and exits 3. The data directory is
|
|
removed when the run ends.
|