319 Commits
Author SHA1 Message Date
jason.woltje 4b35e3c1d2 fix(bus): CB5 re-check, a running or failed revoke outranks copy-service-unbindable; unbind summary tested (#1873)
- copy-launch status(): a fenced or closed copy falls through to the gate check, so the owner
  sees credential-revoking or credential-revoke-failed for a binding issued to a copy whose role
  also needs a service a copy cannot bind.
- copy-bindings: an unbind raise reads change 'unbind' in the raise answer, every inbox and trail.
2026-11-12 19:19:22 -06:00
jason.woltje 56aeefb370 fix(bus,webui,cli): CB5 review fixes, binding summary on the inbox, raise and trail reads, copy-service-unbindable status, Console allowlist (#1873)
- broker: the hire.raise answer, the inbox console preview and the trail read carry a
  binding as {instance, change} only; the raise event keeps the full proposal the resolve reads.
- copy-launch status(): a copy whose role needs a service a copy cannot bind reads
  copy-service-unbindable (new fixed status text) instead of a gitea binding step.
- cli instances: an unbound copy's line names its missing services.
- webui serve: the instances verb rebuilds each copy binding from the fixed status table.
- bus.js reads the binding change field only.
- browser tests: system Chromium starts with --disable-extensions; the A3 booted-bus test passes it.
2026-11-12 19:19:22 -06:00
jason.woltje dbb69c8a41 test(bus,cli): CB5 two-organization acceptance and the CB4 deferred P3 tests (#1873)
The two-org test boots real buses for two organizations with a shipped
Gitea-requiring thread role, binds each copy through its own owner
decision and verified issue, and checks identity separation, record
isolation, token isolation, B through A's revoke, archive and delete,
and refusal of a replayed raw A binding or A token in B.

P3-1 shadowed cleanup, P3-2 runtime revoke wiring, P3-3 ordinary-run
stop. Each passes on BASE; guard-removal mutants recorded.
2026-11-12 19:19:22 -06:00
jason.woltje 808b2b7cbf fix(packs): SP5 review round, broker import closure, no-op spend, role.hire before the read, template-named steps (#1873)
The broker no longer imports organization util or definitions; the proposal
pin digest is digestPrd and the inline composition is built in place, so the
sandbox client import closure project-runtime.test.mjs pins is unchanged.
An agent apply the runtime skips (a repeat that adds nothing) never reaches
beforeWrite and spends no grant. A proposal raise checks role.hire before it
reads the packs list. An agent apply keeps a workflow step only for a pack
role the organization defines or one the pack pins to the template of that
name; an inline definition sharing a template's name is left out. Tests: a
repeat apply spends nothing, apply then raise end to end with the broker
booted from the file, a project pack, the template-name shadow, and a chief
without role.hire; the revision refusal is matched exactly.
2026-11-12 19:05:33 -06:00
jason.woltje 5ffe38e3b2 feat(packs): the chief applies a pack's non-definition half and raises hires from its proposals (#1873 SP5)
pack.preview, pack.apply, board.set and workflow.set accept an agent session whose role
lists organization.change (Jason 11-12 Q2): the check runs before the read, and the grant
is spent once after a write commits. A role without it gets decision-required. The packs
read lists packs for a within-role holder and spends nothing.

An agent apply never writes a definition. A definition a human apply would add is marked
not-written and its hire is pinned to the template or the inline entry. A workflow step
naming such a definition is left out and listed, and a workflow left with no steps is not
written. A definitions rename or a saved template refuses human-required, with the writer's
own guard behind both.

hire.raise takes {proposal: {pack, project?, hire}, route, reason?} from the chief. The broker
reads the recorded proposal, checks an inline pin's hash (starter-pack-proposal-stale) and
launch.noHire, and hands the pin to the hire service, which refuses a moved template or
definition as decision-stale or definition-rev-conflict.
2026-11-12 19:05:33 -06:00
jason.woltje 9a649abf85 fix(packs): SP4 re-check, the board route method split, human role reserved, distinct step roles (#1873)
- serve.mjs: only GET and HEAD /api/board stay the Board read; every
  other method goes to the pack route, so DELETE and PUT answer its 405
  again. The owner-only check moves inside packsHTTP after the method
  check, so OPTIONS on a root Console stays 405 as before SP4.
- runtime.mjs: a --as rename cannot target the definition name human,
  and a human step role never follows a rename. A step whose mapped
  roles collide refuses invalid-request at preview, not only at apply.
- The no-op apply skip also needs the same pack sha256, so a changed
  pack with nothing to add still records its entry.
- Tests: the --as refusals for human, a step role collision, a pack
  defining human, a changed saved pack recording its entry, board by
  PUT, a granted session refused owner-only on every pack route, and a
  Console without sign-in refused owner-only.
2026-11-12 17:17:19 -06:00
jason.woltje 1ba3288bec fix(packs): SP4 review round, --as collisions, step roles, the board route and repeat applies (#1873)
- An --as target that lands on another pack item's name refuses invalid-request
  (definitions and workflows); the preview no longer shows two adds for one path.
- A workflow step role naming one of the pack's definitions follows its --as rename,
  so an inline definition renamed at preview applies.
- GET /api/board stays the Board read; only POST /api/board is the pack board write.
- Tombstones key on pack id, origin and project: a saved template reusing a shipped
  id is another pack.
- An apply that adds nothing and proposes what the last apply proposed writes
  nothing, so retries do not fill the 256 packs entries.
- mosaic org pack list refuses inside an agent run like the other words.
- Tests pin coder-1's credential lines, skills.notEnabled and the member's
  unsuffixed pack.apply and board.set refusals; the CONSOLE_VERBS pins in two bus
  tests name the five pack verbs.
2026-11-12 17:03:56 -06:00
jason.woltje 079ced93f3 feat(packs): pack, board and workflow verbs, routes and CLI words (#1873 SP4)
Design section 8. The bus answers packs, pack.preview, pack.apply,
board.set and workflow.set to the organization's human, and their
.console forms to the owner's Console cap. The broker runs the section 3
merge, the plan digest (pack-plan-stale on a mismatch) and the held
credential check. The organization writer keeps packs, board and
workflows out of the generic write and refuses definition writes to
every actor name an agent carries, project agents included.

mosaic org pack list|preview|apply, board set and workflow set|remove
go over the organization's bus as its human and refuse inside an agent
shell before any file is read. The Console serves GET /api/orgs/<id>/packs,
packs/preview, packs/apply, board and workflows/<name> (POST and
DELETE) to the root owner's session only, writes under --send only.
2026-11-12 16:51:46 -06:00
jason.woltje 95c2ce1435 fix(organization): CB4 re-check, project.remote.set refuses under a copy binding that still grants the project (#1873) 2026-11-12 16:16:24 -06:00
jason.woltje 2196d37a47 test(bus): CB4 tests for the slot parent check, the resume failure code and the CLI copy remote wiring (#1873) 2026-11-12 16:14:06 -06:00
jason.woltje ef1d3a4583 fix(bus): CB4 review round, fire revokes after the write, archive and delete revoke at Gitea (#1873)
Build review (changes 8) and security review (changes 4):
- P1-1: an owner-approved fire no longer writes the revoke before the
  apply (decision-stale). The fire stops the copy's runs, the fire is
  written, then the retire revoke starts for the fired instance.
- P2 (both): archive and delete from the CLI and the Console pass the
  organization's managed Gitea remote step (copyRemoteFor). A remote
  step that was not attempted or failed keeps the record revoking with
  failed remote, so the bus finishes it after restore; no done tombstone
  over a live token.
- Security P2-1: a bound server that cannot be read is a failed remote
  step, not not-managed. updateOrg refuses project-repo-bound when a
  project a copy binding grants loses or changes its remote or git.
- P3-1 (security): a delete whose organization file cannot be read says
  copiesUnreadable, never an empty copy list.
- P3-2 (security): the remote step requires the record's incarnation to
  equal the registry's live one.
- P3-5 (build): the archive's slot discard checks each parent directory
  (no symlink, own uid, private mode).
- P3-6 (build): resume keeps credential-revoke-failed as the gate code
  while a failed op runs again.
- P3-4 (build): a test pins the refused-begin reopen guard.
2026-11-12 16:08:08 -06:00
jason.woltje 90245765f2 feat(bus): copy revoke CB4, lifecycle events fence and revoke bound copies (#1873)
Every lifecycle event that ends a copy's authority (unbind, emergency
revoke, slot removal or expiry, role change, fire, collision, shadowing,
archive, delete and recreate) now closes admissions, drains in-flight
uses, stops runs with a confirmed ack, removes the slot and revokes the
Gitea token through the org admin slot. The binding moves through a
durable revoking state, so a restart resumes the same op and never
resurrects authority; an uncertain outcome stays fenced.
2026-11-12 16:08:07 -06:00
jason.woltje 0b8fe202bc fix(bus): CB3 review fixes, live registry state, read scope, revision to bind (#1873)
- The copy launch gate reads the organization registry entry on every
  check for a verified copy. A state other than active, or a new
  incarnation, refuses credential-revoked; an unreadable registry
  refuses credential-unavailable.
- Repository reads need read or write repository scope, like writes
  need write scope.
- The admitted organization revision travels from the launcher through
  bindLaunch. prepare checks it before and after the live proof, and
  admit checks it after the launch authority; a change refuses
  organization-changed.
- Tests for the completion authority recheck, the broker session
  authority compare and an incarnation change; the copyRefusal comment
  now names where restart-required is answered.
2026-11-12 13:37:46 -06:00
jason.woltje 5f8079a972 feat(bus): copy launch gate CB3, verified bound copies only (#1873)
Materialize only verified bound copies: a binding approved after boot
answers restart-required. Boot and every launch re-resolve the binding
and prove the slot live against its service; unavailable verification,
a partial binding or a stale file refuses. The A3 revision fence and
the launch authority digest ride through prepare, final admission and
bindLaunch. Pending revocation blocks admission and no fence is
released on an uncertain outcome.

Every copy credential call checks session, incarnation, scopes,
generation and liveness, takes the slot from the session, goes only to
the approved origin with redirects refused, and rechecks the generation
at completion. Prepare and boot proofs run inside a time budget so a
silent service cannot stall the host channel. The launcher maps a
copyLaunch refusal to its own code instead of launch-failed.

Tests: copy-launch unit suite, CLI launch and race cases (prepare and
bind races assert no repo call, empty project manifest included), and a
docker acceptance on gitea 1.27.1.
2026-11-12 13:37:46 -06:00
jason.woltje 6d0e9f89be fix(bus): sweep ungranted copy slots at start, clean a failed stage (#1873)
Security review P2: a hard crash after the stage left the staged token
on disk. sweepCopySlots runs at start, before Credentials loads, and
removes each copy service slot whose binding holds no grant, plus any
staged temp file. It never touches a role's slots, a slot a loaded
reference names, or an organization whose document cannot be read. A
stage write that fails removes its temp file, and its slot when the
rename has already happened.

Build review P3s: push is held to the binding's approved level, not the
token's. Tests now cover the boot-copy pre-checks, the format check
running before the stage, and stageCopy's reference refusal.
2026-11-11 17:13:04 -06:00
jason.woltje d5aa963893 feat(bus): copy credential issue CB2, Gitea verified live (#1873)
An owner-issued Gitea token for an agent copy is staged inactive in the
self-only store, proved live against the copy's Gitea (token scopes by
semantic comparison with all and admin refused, the copy's dedicated
per-org/copy/service account, every reachable repository, expiry), then
committed under the writer's generation, revision, decision, copyId,
incarnation and definition-pin recheck. The grant record holds only an
opaque grant id and rotate date. Vikunja refuses
credential-scope-unverified. Copies still cannot launch (CB3).
2026-11-11 17:13:04 -06:00
jason.woltje f0e11cb342 feat(proxy): Console proxy setup page and CLI parity (#1873)
One Proxy setup panel on the Model proxy settings page takes an owner from
nothing to a running proxy: status with one next-step button per state, the
pinned fetch with hash checks, progress and a receipt, init with a
bus-generated key (a pasted key only over loopback or HTTPS, with a
confirmation), unit render/install/start/stop/restart with health, a fence
clear that the bus re-proves against a confirmed restart, and a stale init
lock clear that names its blockers. Own proxy per organization shows as not
built.

New Console routes under /api/proxy/admin/ use the existing owner proxy
checks; agents, testers and grant holders get human-required. New bus verbs
proxy.init {generate:true} and proxy.fence.clear. Receipts go to
<dataRoot>/state/proxy-admin.jsonl with labels and key ids only. Every new
refusal code has a refusal-table entry.

CLI: mosaic proxy status, unit render|status|install|start|stop|restart,
init --generate-key, fence clear --restart, init-lock status|clear; proxy
fetch keeps its stdout and adds progress and the receipt.

Page fix found in the end-to-end run: a stopped proxy hides the account
panels until the service answers. (The catalogue switch label fix found in
the same run landed upstream as D3 P0-4.)
2026-11-11 16:32:31 -06:00
jason.woltje 5dbd7e72d3 fix(org): copy binding review round, CB1 (#1873)
Security review P2s:
- A binding proposal keeps only its structured request fields. The
  free-text reason is never written to the private proposal or covered
  by its digest.
- A root copy's receipts are checked at prepare, at check, and again
  under the organization lock before the write and before publication.
  A copy removed, replaced or unreadable since boot refuses with
  instance-fired, copy-stale or root-policy-unreadable.

Build review P2:
- A root copy's admitted projects come from the project unions,
  recomputed from the current document and the boot's root agents. A
  project that excludes the copy, or whose union refuses, is never in
  reach; a request naming it refuses with credential-scope-exceeded.

Build review P3s: tests for proposal-time shadowing, the loader's
copyBindings validation, a pending record that covers every service,
a stricter path check on the refusal table, and refusal codes on every
bare rejects in the binding tests.
2026-11-11 14:27:08 -06:00
jason.woltje d23673cd3e feat(org): copy credential binding CB0 and CB1 (#1873)
CB0: registry incarnation minted at reserve (legacy entries get one at
the first binding proposal, under the registry lock); copyId, source
and definition pin, binding generation; a pure resolver where
effective = role intersect approved and only a bound, matching,
unshadowed record resolves.

CB1: copyBindings in the organization file (ids, scope names, project
ids and integers only). applyCopyBindingDecision is its only writer,
behind a module-private capability every other commit is fenced
against. A binding is an owner-only subtype of the hire decision:
only the chief raises it, no autonomy level, resolver agent, member
right, tester or reader resolves it. Digest, expiry, single
consumption, revision, generation, incarnation and definition pin are
rechecked before any effect; a bind writes pending, an unbind the
unbound tombstone, receipts are paths only. Nothing writes bound, so
nothing launches on a binding yet (CB2/CB3). The org service and the
Console update path keep copyBindings server-held. Eight new refusal
codes with next steps.
2026-11-11 14:27:08 -06:00
jason.woltje ff20efb819 fix(autonomy): review round for #1873 account coverage
A replaced installed harness answers null for countsAccount until the
bus restarts and reads the new module. A runtime test pins the
startBroker wiring for claude-code (covered) and pi (refused). The
plugin README says countsAccount also decides authority coverage and
is read once at start.
2026-11-11 13:46:22 -06:00
jason.woltje cfe7535533 fix(autonomy): account quota coverage reads the harness module's countsAccount, not a name (#1873)
authorityBudgetCovered named claude-code to decide whether an account
quota covers every future launch, which fails the row 65 scan. The bus
host now passes each harness module's own countsAccount answer, read
once with its levels in harnessLevels, through autonomyHost to the
broker. Without the lookup no account quota counts (fail closed); the
provider/model branch is unchanged.
2026-11-11 13:39:44 -06:00
jason.woltje b1fc96f4ae fix(routes): name Disable only when it makes the save apply (P0-4 review)
The catalogue refusals no longer tell every user to press Disable model
proxy catalogue. The server text names the proxy setup step. The Routing
page adds the Disable step only when cliproxy is listed and every moved
model comes from another listed provider, and sends a tester to the
owner. The switch mismatch message no longer claims a setting changed.

Tests: a fallback thinking-only change saves with no catalogue; a move
between model-proxy models refuses before and after cliproxy is removed.
2026-11-11 13:35:56 -06:00
jason.woltje 967025f749 fix(routes): fixture routes, thinking and limits save without a model catalogue (P0-4)
A fixture-only organization reads a ready catalogue with no model proxy
client: the catalogue asks the proxy only when a module calls it.
A thinking-only change, and a limits patch that keeps harness, model and
entry, no longer asks the catalogue. A change that truly needs it still
refuses, and the WebUI names the next step: keep the model and change
thinking, or press Disable model proxy catalogue. The Routing switch
follows whether cliproxy is listed and removes or adds only cliproxy.
2026-11-11 13:35:55 -06:00
jason.woltje 88a94ddd34 test(bus): pin the autonomy budget helper import (#1873) 2026-11-11 10:27:41 -06:00
jason.woltje 2d4b07e516 fix(org): retain committed inverse status through completion IO failure (#1873) 2026-11-11 10:27:41 -06:00
jason.woltje e3232b814f fix(org): enforce autonomy budgets and durable inverse boundaries (#1873) 2026-11-11 10:27:41 -06:00
jason.woltje 0ef6326084 feat(org): add per-class autonomy and guarded reversals (#1873) 2026-11-11 10:27:41 -06:00
jason.woltje 16cdf5cdc1 fix(organization): an approved hire and the boot copy definitions run the definition check (#1873)
The hire service takes the bus's definition check as scanDefinition and runs
it on the stored proposal entry before preview, check or apply goes further,
and on the approved entry again just before the writers. An approval whose
definition holds a credential the store came to hold after the raise refuses
definition-holds-credential before the decision is consumed; nothing is
written. Without the hook the entry still goes through assertClean whole.

Bus start and credentials.issue also check the boot copy snapshot's
definitions (A4 root agents file definitions, re-applied on every reload),
which no organization file holds.
2026-11-11 08:49:15 -06:00
jason.woltje 1a45a7274b fix(organization): credentials issue and rotate refuse a value already in an organization definition (#1873)
credentials.issue runs a check after it normalizes the value and before the store, the
organization file or memory changes: the value must not appear in the definitions of any
organization the bus serves (instructions, personality and every other field or key). A hit
refuses definition-holds-credential naming the organization, definition and key, never the
value or the credential. An organization file the check cannot read refuses
definition-scan-unreadable (new TI entry). The check runs on the bus loop inside issue, so a
launch admission can no longer pass and then see its definition text become held before spawn.
The final admission re-scan stays as the backstop for values held outside the verb.
2026-11-11 08:49:15 -06:00
jason.woltje 17eecb2d65 fix(organization): final launch admission re-checks the org definition against held credentials (#1873)
Review round (P2): a credential issued between the launcher's definition scan and
spawn could make text already in the definition a held value; a same-date rotate
leaves the organization file's revision unchanged, so the revision fence missed it.
The bus's final request.admission for an instance, the last bus op before spawn,
now runs the held-secret check on the org: definition the instance names, on the
bus loop that issue runs on, and refuses definition-holds-credential.

Self-found: check() takes the scanned entry from the same read as resolveInstance,
before any await can let another check replace the shared organization.
2026-11-11 08:49:15 -06:00
jason.woltje 8fec494694 fix(organization): bus start and launch check org definitions against the held credentials (#1873)
T1 follow-up. A definition's text becomes an agent's contract, but a load ran the
held-secret check with an empty store. Bus start now checks every definitions entry
(the boot copy's org: entries and the file's own) with the live store, and the
launch check asks the bus the same question for the org: definition it just read,
before a contract exists. A hit refuses as definition-holds-credential, a new code
in the refusal table; the refusal names the definition and key, never the text or
the credential. bus start records the refusal in the boot status.
2026-11-11 08:49:15 -06:00
jason.woltje 5e93356cfa fix(authority): close chief grant and root fire review gaps (#1873) 2026-11-11 04:19:33 -06:00
jason.woltje 89205a6163 feat(authority): resolve hire, fire and role changes through pinned human decisions (#1873) 2026-11-11 04:19:33 -06:00
jason.woltje b7c9eee603 fix(organization): definition writes go through the bus with the held-secret check (#1873)
Review P1: the CLI wrote definitions with a no-op secret check. setDefinition
now refuses definition-secret-check-required when a write that adds or changes
an entry has no assertClean. New bus verbs definition.import|invent|edit|remove
run the writes for the business's human at the cli with the credential
store's assertClean; the tester, agents and readers refuse. The CLI's
definition writes call the bus and map its codes to messages that never
quote the definition.
2026-11-11 01:15:12 -06:00
jason.woltje b44b14c7df feat(plugins): install pinned instance packages and declared tools (#1873) 2026-11-11 00:11:13 -06:00
jason.woltje 17a48217f6 fix(agents): A3 project unions reach every agent, copies never collide or shadow (#1873)
Review fix round for slice A3.

- Every project's union is recomputed from the current organization file
  at each load. A refused union refuses the project's own copies and every
  inherited root or org agent there: no mount at launch (checkout-skipped,
  project-refused), no thread and no room, each naming the project and why.
- A project exclude removes that project's mount from the excluded agent;
  a narrow reaches the instance's resolved limits, so its real bundle is
  narrowed. A narrow in any project narrows the instance for every launch,
  since one launch mounts every project it works in.
- Two copies whose instance names collide both refuse, naming each
  claimant; the view lists the claimants. An organization instance of the
  same name replaces a root or project copy, at boot and after it, and the
  copy is gone rather than refused.
- Rooms hold only the thread instances that work in the room's project.
- The grid finds an agent's copy by name and project from the bus view,
  never by rebuilding the instance name.
- Real-boot regressions: inherited agents in a refused union, exclude and
  narrow in the bundle, an org override after boot, two organizations each
  running a copy, a root file change while running, and a grid fed by a
  booted bus.
2026-11-10 20:27:33 -06:00
jason.woltje 9d00f9ad54 feat(agents): A3 root and project agent copies at bus boot (#1873)
Each root agent an organization does not exclude, and each agent a project
defines, becomes a copy when the organization's bus boots. The root file is
read once, through loadRootAgents, at the cli boot step; the snapshot is fixed
until the next boot. A bound copy joins the organization document's roles and
goes through validateBusinessDocument and checkRoles with the organization's
own credential map. A copy whose role needs a credential service is unbound
and refuses at launch by name and service (credential-unbound); a copy the
organization refuses is copy-refused; every agent in a project whose union
refuses is project-refused, naming the project. A project agent launches
only with its own project's mounts and takes a thread only in its project
(project-agent-elsewhere). Refusal events carry the code alone. The bus's
instances read carries the copies with their running runs, and the Agents
grid shows each copy's real status and reason.

channel-proof re-pins webui bus.mjs for four STATUS entries; no proof or
transport change. packages/business gets the agent-copies.mjs re-export.
2026-11-10 20:27:33 -06:00
jason.woltje ddf4f895cd fix(rails): close review guidance and coverage gaps (#1873) 2026-11-10 19:42:36 -06:00
jason.woltje 7035ce61b3 feat(harness): expose caller rails and refusal guidance (#1873) 2026-11-10 18:51:15 -06:00
jason.woltje e9a079fcc4 fix(organization): validate narrowed arbiter resolve authority (#1873) 2026-11-10 16:51:03 -06:00
jason.woltje 7de9cfccc3 feat(organization): enforce arbiter domain resolve rights (#1873) 2026-11-10 16:33:21 -06:00
jason.woltje a7b2199390 test(bus): pin person handlers to their vocabulary (#1873) 2026-11-10 13:32:55 -06:00
jason.woltje f5cc712a59 feat(bus): export and pin person task verbs (#1873) 2026-11-10 13:32:55 -06:00
jason.woltje 364f1ae7a6 fix(tasks): U4a review fixes for the built-in task store (#1873)
Six review findings, one round:
- A selected task-tracker module that fails to load or has no factory refuses boot with tracker-config.
- The expect digest covers the task revision, so archive and unarchive invalidate an old token.
- Position exhaustion and an occupied explicit position refuse task-position-full; no rebalancing yet.
- The store adapter reads roles from the broker's current business document (Broker.taskRoles), so a role added by reload works.
- Only newly requested assignees are checked against live roles; stored ones survive edits, archive and delete.
- Human tasks.create requires a requirement citation (REQ-AREA-N); tasks.edit accepts one.
2026-11-09 19:55:25 -06:00
jason.woltje 9b7bf11afb feat(tasks): U4a, a task store built into each organization (#1873)
PRD 1.20 REQ-TASK-1, REQ-PLUG-1, REQ-WS-8. Each organization keeps its
tasks in its own bus through the new task-tracker plug-in kind. The
default module is the built-in store; Vikunja is the optional module
and a Vikunja organization keeps today's path.

- bus schema 3u to 3v (migration 3u-3v.sql): store_tasks, append-only,
  one row per write, each citing its events row; seven guard triggers.
- broker: the eight role verbs on the store with the slice 1 field
  table checked twice (module, then a before/after field diff); the
  person's tasks.create/edit/archive/unarchive/delete as human.input
  events; the tasks read returns store rows in board order (group,
  position), filtered and paged like tracker rows.
- runtime: each business gets its module at start (organization file
  plugin, else vikunja with a tracker entry, else store); a store
  business with a Vikunja tracker refuses the boot (tracker-config).
- plugins: task-tracker kind with store and vikunja modules.
- cli: the launcher's tracker flag covers store organizations; trail
  prints store writes.
- pins: schema.test counts, the bus migration tests, stack-release #811
  and T46 (store_tasks on the always list; COUNTED unchanged),
  budget-supervisor accepts 3v.

Rebased onto SYS1 by the lead: SYS1 took 3t-3u, so this step is 3u-3v.
2026-11-09 19:25:44 -06:00
jason.woltje f4bfd3a744 feat(plugins,organization): system types as a plug-in kind (REQ-SYS-1, #1873)
Adds the system-type kind with five modules (coding, creative-writing,
marketing, montage, business-management), an org-level enabled list
validated fail-closed, project selections limited to the org's list,
read verbs, and bus migration 3t-3u. REQ-SYS-2 toolsets are designed and
deferred: they need a role authority contract.
2026-11-09 18:46:35 -06:00
jason.woltje d35447005a Isolate invalid workspace reads and cancel timed-out org work 2026-11-09 18:22:27 -06:00
jason.woltje 7a97cfc4f3 fix(bus): make the private store root at start when a reference names the store (#1886)
Adding an agent with a store credential on an instance with no
<configDir>/secrets/agents left the bus unable to start
(credential-file): Credentials refuses a missing store root, and only
issue() made it, which needs a running bus. Start now makes the root
(0700) the same way issue() does, only when some reference has
store: true. Credentials' own refusal (credential-store T1) is unchanged,
and a root with loose modes or a symlink still refuses start.

Tests: two new credential-verbs tests; the creation test fails on
483eccb3d with credential-file. All 171 bus test files run one at a
time: 1713 pass, 0 fail.
2026-11-09 17:10:09 -06:00
jason.woltje 03fe321b12 docs(prd): land version 1.20, the unified workspace (#1873)
Jason approved draft 2 on 2026-11-09 at 22:57Z: "The file looks fine
other than that." The exception is the Montage module name, deferred
since 19:26Z. Amends REQ-ASSIST-1, REQ-USER-1, REQ-TASK-1 and REQ-WEB-3
and adds 17 requirements (101 to 118): REQ-WS-1..8, REQ-AGENT-1..3,
REQ-SYS-1..2, REQ-ACCT-1..2, REQ-SETUP-1..2. requirements.json and the
tasks and bus count pins follow.

Tests: 68 pass, 1 fail. The failure is stack-copy.test.mjs (20/1), which
fails the same way on origin/refactor 483eccb3d: npm's pinned install
can't find node-gyp/bin/node-gyp.js in the test Node installation.
2026-11-09 17:04:31 -06:00
jason.woltje bad760ce08 Merge refactor fbf2f6fc8 (rename stage B) into F2
Conflict in packages/webui/src/serve.mjs imports: kept F2's
THREAD_DEFINITION and onboarding imports on stage B's organization path.
The F2 assistant test edit followed the move to packages/organization;
onboarding-browser now imports the organization service directly.
2026-11-09 13:17:33 -06:00