243 Commits
Author SHA1 Message Date
jason.woltje e6ab8bc1fd feat(bus,plugins,organization,cli,webui): SP9 remove system types outright, bus schema 3v-3w drops project_system_types (#1873)
Jason's 2026-11-12 ruling: the only deployed system is the dev environment on
dragon-lin, so the system-type plug-in kind goes with no retired kind, fence,
conversion or new refusal code.

- plugins: system-type leaves KINDS; system-types.mjs and the five modules are
  deleted. An org file naming the kind refuses unknown-kind.
- organization: the plugins.system-type check, systemTypesFence and the
  system-types.console right are removed.
- bus: system-types.console, project.system-types[.set], the system-type half
  of the tester check, the runtime reads and system-type-not-enabled are
  removed. Step 3v-3w drops project_system_types, its index, its four guards
  and its rows; SCHEMA_VERSION is 3w (32 tables, 126 triggers, 5 views).
- cli: mosaic org system-types and mosaic project system-types[-set] are
  removed; stack-release COUNTED and the budget supervisor's closed list move
  to 3w.
- channel: the project.system-types verbs are removed.
- webui: the System types page, route, dashboard row, chips and project
  selection are removed.
- docs: REQ-SYS-1/2 now describe starter packs; README system-type text and
  the requirements titles follow.
2026-11-12 21:02:46 -06:00
jason.woltje 0251acdad9 fix(packs): SP8 re-check, close before unlink cannot skip it; check the whole reason before the cut (#1873) 2026-11-12 20:05:32 -06:00
jason.woltje 13560660ae fix(packs): SP8 review round, single-pass placeholders, CLI hints, pins (#1873)
- template-save: one alternation pass replaces every literal, so an
  instance named root, org or agent never rewrites a placeholder already
  written in. checkPack's refusal message is passed on as the reason. A
  write or fsync failure removes the partial file it created.
- broker #templateFail drops a reason the credential check refuses.
- cli template words: humanTransport throws a CliError named by the bus
  code; a known code now gains its hint (the test transport throws the
  same CliError).
- template-http: the header notes serve.mjs strips /api/orgs/<id>.
- pins: the two .console verbs in console-decide and request-console;
  the packages/business/src re-export for template-save.mjs.
- tests: placeholder collision, a held-value key masked as [key], and a
  save after a real pack.apply.console keeping {id, version}.
2026-11-12 20:05:32 -06:00
jason.woltje 08e50e513f feat(packs): the owner saves an organization's shape as a template (#1873 SP8)
template-save.mjs captures the org (or one project) as a starter-pack JSON under
<config>/templates/<owner>/<name>.json: copy material and instance credentials
stripped, role credential request lines kept, owner/org/project/agent/root names
replaced by placeholders in free text, at most 8 hires, packs entries {id, version}.
A held credential value in kept text refuses template-secret-suspected naming the
field path. Preview then save with the preview's digest; O_EXCL 0600 write, a
second save refuses.

Bus: template.save/template.list for the owner's CLI cap, .console names for the
owner's Console cap, null in VERB_RIGHTS. CLI: mosaic org template save|list.
Console: GET /api/templates, POST /api/templates/preview, POST /api/templates.
2026-11-12 20:05:32 -06:00
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 fdbc34413b feat(webui,bus): CB5 Console operator flow, binding confirmation and next steps, copy binding status on the Agents grid (#1873)
The bus instances read adds a copy's binding status only when the copy was
bound at boot or is unbound for want of a bindable service, never to a
tester. decision-http returns an allowlisted binding (instance and change)
on a binding confirmation and fixed next-step text on an approved resolve
and on a binding hire start. The decision page names the copy and the
change; the receipt shows the next step; the Agents grid shows can't launch
with the binding's next step. Every new string is fixed text.
2026-11-12 19:19:22 -06:00
jason.woltje c5bf71ab08 feat(bus,cli): CB5 operator status, each copy's binding status and next step in the owner's instances read and mosaic org instances (#1873)
The launch gate's status() runs the same checks a launch runs, without the loss report, and
answers a fixed { status, next } from organization copy-binding-status.mjs (design section 6
texts plus issue-required and ready). A tester's read never carries it.
2026-11-12 19:19:22 -06:00
jason.woltje 34dd331016 fix(packs): SP5 re-check, the inline pin digest is canonicalJson's for integer-like keys (#1873)
digestPrd rebuilds an object, so integer-like keys come first and the JSON
differs from canonicalJson, the digest the pack apply records. An inline
entry with such a key (a credential scope map group) refused as stale on
every raise. The broker now builds the canonical string itself, a local copy
of util.mjs canonicalJson, so the sandbox import closure is unchanged.
2026-11-12 19:05:33 -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 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 ff33b19854 feat(plugins): starter-pack kind and its checker (#1873 SP1)
KINDS gains "starter-pack" (interface 1, export starterPack) with a new
switch "none": namesFor refuses any setting for it with bad-setting, so an
org file can never switch a pack on through plugins.

starter-pack.mjs adds checkPack(doc, {origin}), narrowsTemplate and
widerLines (step 7's line rules), installedStarterPacks (shipped and
installed packs through loadInstalled, origin set; a refused core pack
fails the listing, a refused installed pack is omitted and logged) and
readSavedTemplate (account against ID_PATTERN, name against NAME, then
lstat, no symlink, owner uid, mode 0600 or narrower, 256 KiB checked
before the read, then parseJsonFileText and checkPack with origin saved).

refusals.mjs gains starter-pack-invalid, starter-pack-not-found and
starter-pack-template-changed.
2026-11-12 15:38:01 -06:00
jason.woltje 2ad4b30ebd fix(org): repo set refuses under a copy binding that still grants the project (#1873 F7)
A copy binding grants the repositories its projects' remotes name when a
credential is issued, and its decision records only project names. repo set
(CLI, route, Settings tab) is now refused with project-repo-bound while a
pending or bound copy binding names the project, before any check, origin
change or write, and again under the lock. The message names the copies and
the next step: revoke the binding, set the repository, raise a new binding
decision. An unbound binding, or none, behaves as before. Bindings are read
from the loader-validated document; binding, launcher and broker code are
unchanged. New refusal-table entry for project-repo-bound.
2026-11-12 13:39:26 -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 75f6d5533a fix(proxy): review fixes for the Console proxy setup page (#1873)
Security review:
- Release verification cache keys on ctime as well as mtime, in
  nanoseconds. A same-size rewrite with mtime set back now re-hashes and
  reports proxy-install-invalid.

Build review:
- The setup page hides the account panels on any failed accounts read, not
  only proxy-down, and brings them back once the proxy answers.
- The organizations table shows a dash, not a made-up 0, when a bus does
  not answer or sends no model list (orgCatalogue in proxy-admin.mjs).
- A fence clear the bus did not answer keeps the confirmed restart for a
  retry.
- A fence with no readable time names `mosaic proxy fence clear
  --proxy-restarted` on the page, in the refusal table and in the README.
- CLI `init --generate-key` goes through the setup controller and writes
  the same init receipt as the page.
- Status carries the last ten receipts, so the page shows them after a
  reload. An initialized proxy keeps the init form folded.
- README: proxy-admin-busy is per process; the cross-process locks that
  serialize the writes are named.
2026-11-11 16:32:31 -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 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 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 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 99ce579e3c fix(plugins): keep imports on the verified package pin (#1873) 2026-11-11 00:11:13 -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 82dcba2d45 fix(agents): A3 hidden checkouts cover every left-out project and refuse links, final admission binds the organization revision (#1873) 2026-11-10 20:27:33 -06:00
jason.woltje 29f7c3af85 fix(agents): A3 excluded checkouts hidden, launch boundary rechecks unions, reload collisions and changed defines refuse (#1873)
- A checkout an earlier launch left for a project the instance may no longer
  work in is covered by an empty tmpfs inside the sandbox; the host copy stays.
- The launcher rechecks every prepared project against the reloaded document
  after preparation, and the bus's final admission takes the instance and
  checks the broker's current unions.
- A project define whose vars changed since boot refuses its copy until the
  next start.
- Instance-name collisions are recomputed at each reload from the frozen root
  claims and the current project defines; every claimant refuses.
2026-11-10 20:27:33 -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 7de9cfccc3 feat(organization): enforce arbiter domain resolve rights (#1873) 2026-11-10 16:33:21 -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