vikunja: Q61a re-mint, pm key 8 and sync key 9; rows A and B brief; decision 86 (sage)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -1811,3 +1811,33 @@ which stay with him. Each item names who decided it and what happened.
|
||||
- Open: projects.create for the pm (asked of Jason via Mos), and Q61
|
||||
(which project the bus watches). Project 32 stays deleted. Jason
|
||||
removed it as a duplicate of #19, and recreate.mjs is gone.
|
||||
86. **The agents bind the bus to #19 and follow nested projects (2026-10-11,
|
||||
Q61a).** Jason, relayed by Mos: "just share them. Get it done. You
|
||||
keep wanting me to do all the manual steps." The agents do every
|
||||
step, and Jason does none of them. This replaces the holds in 85.
|
||||
- ops-01 inserts the team shares on #3, #4 and #33 (team 1 at admin,
|
||||
team 2 at read). Access cascades to their descendants.
|
||||
- Keys re-minted with "full agentic access" and still no task or
|
||||
project delete, no duplicate and no share, team, user or webhook
|
||||
route (Q60). The pm is key 8: key 7's scopes plus projects create,
|
||||
views_buckets, views_buckets_put and views_buckets_post, and
|
||||
projects_views read_all and update. The sync bot is key 9: key 6's
|
||||
scopes plus projects read_all. Keys 7 and 6 are revoked and answer
|
||||
401. Evidence: `agents/sage/work/vikunja-setup/2026-10-11_remint.json`.
|
||||
- The bus binds to #19 "Mosaic Stack". Its kanban gets the five
|
||||
buckets by renaming where the mapping is obvious (To-Do to todo,
|
||||
Doing to in-progress, Done to done) and adding in-review and
|
||||
blocked. Jason's tasks stay where they are. A before-state file
|
||||
comes first.
|
||||
- Child boards are watch-only. The agents never rename or add
|
||||
buckets on them.
|
||||
- Rows A and B (`docs/plans/2026-10-11_multi-project-sync.md`):
|
||||
read-only nested sync now, and verbs across the tree after row A
|
||||
is done. Mos ruled that task.create takes an optional project,
|
||||
which must be an installed project in the tree.
|
||||
- Correction to 85: no adapter archive guard is needed now. The
|
||||
adapter has no project verb, so the pm's projects.update can't
|
||||
reach a project through the bus. The row that adds a project verb
|
||||
adds the guard.
|
||||
- Projects.create is used once now, for "SetSpark" and "Launchpad"
|
||||
under #33, with no tasks.
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# Multi-project sync: rows A and B (2026-10-11)
|
||||
|
||||
Status: written by Sage, lead. It follows `docs/plans/BRIEF-TEMPLATE.md`.
|
||||
Jason answered Q61a, relayed by Mos: agents see and work his nested
|
||||
projects ("just share them. Get it done."). Mos ruled the shape: row A
|
||||
now, row B after row A is done, and task.create takes an optional
|
||||
project. Lead decision 86 records it.
|
||||
|
||||
Three constraints hold for both rows. A change that breaks one of them
|
||||
is out of scope, whatever else it fixes.
|
||||
|
||||
- A task's ledger ref stays `vikunja:<project>/<task>`. The ledger
|
||||
checks that form on `task_snapshots`, `decisions` and the `events`
|
||||
subject (`packages/bus/schema.sql`), and `task_snapshots` is
|
||||
append-only. Neither row changes `packages/bus/`. Never key a task by
|
||||
its id alone.
|
||||
- `tracker.descendants` defaults to false. With it false, the adapter
|
||||
behaves exactly as v0 does, and every v0 test passes unchanged.
|
||||
- The adapter never writes to a board. A child project is installed
|
||||
only if its one manual kanban view already has the five buckets
|
||||
(`todo`, `in-progress`, `in-review`, `blocked`, `done`), done and
|
||||
default wired, as the root's install check requires. Any other child
|
||||
is watch-only. No bucket, view or project write ships in either row.
|
||||
|
||||
## Multi-project sync: the adapter reads a project tree (row A)
|
||||
|
||||
### Problem
|
||||
|
||||
The adapter watches one project. `settings()` takes one
|
||||
`tracker.project` (`packages/tasks/src/adapter.mjs:21`), startup checks
|
||||
that project alone (`startup.mjs:37`), and sync reads its board and task
|
||||
list only (`sync.mjs:21`, `sync.mjs:45`). A task in any other project is
|
||||
a shape error in the walk (`sync.mjs:59`), and a move to another project
|
||||
is a tombstone (`sync.mjs:123`). Jason's projects nest. The bus binds
|
||||
to #19 "Mosaic Stack", and he wants agents to follow work into its
|
||||
child projects.
|
||||
|
||||
### Owner and reviewer
|
||||
|
||||
- Owner: Darkwing.
|
||||
- Reviewers: Dewey and Filbert.
|
||||
|
||||
### Files owned
|
||||
|
||||
- `packages/business/src/vars.mjs` and `packages/business/tests/vars.test.mjs`
|
||||
- `packages/tasks/src/adapter.mjs`, `startup.mjs`, `sync.mjs`,
|
||||
`fake.mjs`, `vikunja.mjs`, `index.mjs`
|
||||
- `packages/tasks/tests/` (all files and fixtures)
|
||||
- `packages/tasks/README.md`, `packages/tasks/live/README.md`
|
||||
- `agents/darkwing/work/queue-<row>/`
|
||||
|
||||
`verbs.mjs` is read-only in this row. Verbs keep refusing a task outside
|
||||
the root with `task-project`, as they do now.
|
||||
|
||||
### What ships
|
||||
|
||||
- `tracker.descendants`, a project-layer boolean var, default false.
|
||||
`tracker.project` stays the root.
|
||||
- With descendants on, the tree is the root plus every descendant the
|
||||
sync bot can see through `GET /projects` (key 9 has `projects
|
||||
read_all`), followed by `parent_project_id`. Discovery runs at startup
|
||||
and at each reconcile, not each tick. Archived projects are not in the
|
||||
tree. Record your rule for a project that leaves the tree (archived,
|
||||
moved out, unshared or deleted) in the README and test it. Its tasks
|
||||
become `task.missing` with a reason. The ledger is never rewritten.
|
||||
- Install state per project. The root's install check refuses the
|
||||
business, exactly as today. A child that passes the same check is
|
||||
installed. A child that fails it is watch-only and never refuses the
|
||||
business. Sync records title, done, assignees and comments for a
|
||||
watch-only child, and no bucket state.
|
||||
- Sync covers each project in the tree. A task moved between two
|
||||
projects in the tree gets the `moved` tombstone naming the new project
|
||||
and a snapshot under its new ref. A move out of the tree stays the
|
||||
tombstone it is today.
|
||||
- Poll cost. Probe whether v2.7.0 serves a cross-project task read to the
|
||||
sync key's scopes. If it does, use one read per tick for the tree. If
|
||||
not, read per project and state the per-tick call count in the README.
|
||||
The probe results go in `agents/darkwing/work/queue-<row>/probes.md`.
|
||||
- `fake.mjs` models `parent_project_id`, the project list route,
|
||||
archived projects and access inherited from an ancestor's share.
|
||||
- Tests: descendants off matches v0; a three-level tree; a watch-only
|
||||
child keeps the business ready; a root without buckets refuses; moves
|
||||
root to child, child to child and child to outside; a new child appears
|
||||
at reconcile; a child leaves the tree.
|
||||
- Gate suites: `node --test 'packages/tasks/tests/*.test.mjs'`,
|
||||
`node --test 'packages/business/tests/*.test.mjs'`,
|
||||
`node --test 'packages/bus/tests/*.test.mjs'`, and every
|
||||
`scripts/test-*.sh`.
|
||||
|
||||
### Out of scope
|
||||
|
||||
Verbs on child projects (row B). Any change to `packages/bus/`. Any write
|
||||
to a Vikunja board or project. An archive guard: the adapter has no
|
||||
project verb, so the pm's `projects.update` can't reach a project through
|
||||
the bus. A row that adds a project verb adds the guard.
|
||||
|
||||
### Gate
|
||||
|
||||
Dewey and Filbert approve on the issue, naming the candidate manifest.
|
||||
The suites above pass on Sage's gate rerun. Sage then runs one live read
|
||||
against tasks.woltje.com with descendants on, root #19, read-only, and
|
||||
attaches the tick log.
|
||||
|
||||
## Multi-project verbs: task verbs across the tree (row B)
|
||||
|
||||
### Problem
|
||||
|
||||
After row A, the bus sees child projects but can't act in them.
|
||||
`target()` and `relation()` refuse a ref from another project
|
||||
(`verbs.mjs:74`, `verbs.mjs:79`), `read()` refuses a task that isn't in
|
||||
the root (`verbs.mjs:88`), and `task.create` always posts to the root
|
||||
(`verbs.mjs:355`) with no project argument.
|
||||
|
||||
### Owner and reviewer
|
||||
|
||||
- Owner: Darkwing, after row A is done.
|
||||
- Reviewers: Dewey and Filbert.
|
||||
|
||||
### Files owned
|
||||
|
||||
- `packages/tasks/src/verbs.mjs`, `fake.mjs`
|
||||
- `packages/tasks/tests/verbs.test.mjs` and fixtures
|
||||
- `packages/tasks/README.md`
|
||||
- `packages/harness/src/tools.mjs` (the `task_create` tool schema gets
|
||||
the optional project) and its test
|
||||
- `agents/darkwing/work/queue-<row>/`
|
||||
|
||||
### What ships
|
||||
|
||||
- Mos's ruling: `task.create` takes an optional `project`. It must be an
|
||||
installed project in the tree; a watch-only or unknown project refuses
|
||||
with a new code the README names. Without it, the task goes to the
|
||||
root, as today.
|
||||
- `target()`, `relation()` and `read()` accept a task in any installed
|
||||
project of the tree. A bucket move uses that project's own view and
|
||||
buckets, not the root's.
|
||||
- A verb on a task in a watch-only project refuses with the same new
|
||||
code.
|
||||
- Tests for each verb across two installed projects, a watch-only refusal
|
||||
and a relation between projects.
|
||||
- Gate suites as row A.
|
||||
|
||||
### Out of scope
|
||||
|
||||
Project verbs (create, rename, archive, move). They need their own
|
||||
brief, an archive guard and a ruling.
|
||||
|
||||
### Gate
|
||||
|
||||
Dewey and Filbert approve on the issue, naming the candidate manifest,
|
||||
and the suites pass on Sage's gate rerun.
|
||||
Reference in New Issue
Block a user