Starts the fixture provider's loopback endpoint for a named dev instance and records it under the data root. Refuses the default instance, a configured proxy, provider credentials in the environment, a non-loopback bind and a second fixture. fixtureLauncherOptions hands the endpoint to the launcher as its session proxy context.
Jason's owner report 2026-11-06: no way to archive or delete projects.
Archive is the reversible half; delete stays out of scope because project
and run records are write-once evidence.
- project.archive / project.unarchive: human-only (project.create's gate
minus the tester carve-out; tester, user and agent refused). State is the
latest row of a new append-only project_archives journal (3s->3t, additive;
the rows are the audit trail), so projects itself never changes and nothing
is deleted. Repeats refuse project-already-archived / project-not-archived.
- project.list hides archived projects until {includeArchived:true}, which
flags each with archived:true; a user still lists granted projects only.
- While archived, thread.create, thread.send, room.open and room.send refuse
project-archived; every existing record stays readable and unarchive
restores everything.
- Console: new public/project-archive.js (+css) and project-archive-http.mjs
routes (chatHTTP's write fence); chat.js gains two one-line hooks,
index.html one script and one link tag; styling only through the shell's
.project-archive-control / .project-archived-filter hooks.
- CLI: mosaic project archive|unarchive <name-or-id> and list --archived.
- stack-release COUNTED/LISTED gain project_archives (schema order); schema
step-count pins and migration fixtures updated for 3t.
bus 1601/1601 (Node 24; Node 26 has the pre-existing project-file socket
stall), webui 582/582, plugins 132/132, cli 1191/1194 (two pre-existing
load flakes of the row253 C4 and land_work families; both pass isolated and
the base commit's full suite fails four of the same family).
Lifecycle Task 2 (#797). A confirmed new-project selection now becomes a
usable product: the code checkout, the organization mapping, the records
repository with the original intent as the owner's spec commit, the chat
association and the working repository, each journaled as its own receipt
(bootstrap:<plan_digest>:<step>) and recoverable after a kill.
- business: addProject is a private exact-add writer under the existing
organization lock and receipt discipline; hold runs a synchronous check
under that lock; findAddition recovers a prepared receipt. Ordinary
writers still refuse every project change.
- bus: prepareBootstrap and executeBootstrap; activateManagedProject
reloads only a receipt-backed additive root and admits it to the broker
after readiness; request.admission host IPC op for the launcher.
- #800: the bound organization revision and association are re-verified
inside the organization lock at the start of execution; a mismatch
records request-plan-stale and performs no effect.
- cli: trackerFor skips reserved products; the launcher refuses to clone a
product the bus has not admitted.
- seat: initializeWorking seeds the working repository, host-only, with no
work ref or push authority.
- schema: append-only migration 3o to 3p widens the request_events kind
list with bootstrap.stale and bootstrap.completed.
Route selection moves into one helper, pickRoute(proxyOf), that both checks call: the
primary preflight, and the fallback with its own preflight only when the primary's
fails, with the same messages. The final check passes proxyFor and is otherwise
unchanged. The first check of a proxy launch passes a stand-in session proxy (marker
key PENDING_ADMISSION_KEY and the configured loopback base URL), which reaches only
the preflights, then runs gate() with a null session proxy on the predicted route only.
The round 1 union over both routes is gone.
The managed fixture takes extra (more harnesses switched on), real (harnesses loaded
unfaked) and hostEnv. Seven tests in proxy-launch-order.test.mjs.
F1: with system.proxy set, the first launcher check no longer returns
before the account, sandbox, capacity and limit checks. It skips only the
harness preflight and the session proxy key match, which need the key P2
admits in startLocked. A launch that can never start now refuses before
authorizeLaunch, the workspace and checkouts, and modelPreflight. The first
proxy pass accepts only credential "proxy" for a declared account, tries
the fallback model when the primary refuses, and lets mayLaunch
key-quota-no-model-key through so P2 can issue the first key. The final
check is unchanged and still runs before newRun and spawn.
F4: the proxy test option is renamed testProxy and createLauncher throws
test-proxy-refused when it is given with system.proxy.
launch-account.test.mjs is a second caller, so the option stays.
Tests: proxy-launch-order.test.mjs (6), launcher.test.mjs F4 throw test;
the managed launch fixture gains bwrap, admit and trace.ops.
Source-candidate: poe d9a564e6d20f5f0fd75ce45b12cbbf8bb4c9d568\nSource-candidate: magica38ba5762b06716db1dee00d0afec162656488f5c\nValidated321whole-file phase plus whole bus1349/model-proxy100/webui490; final gate tooling checks pending, not landed.
Guard, limits, M11 fence, broker guard/page store/check event, BusError
reason, runtime wiring and the CLI replies verb. No runner work, no tests,
nothing run. BUILD.md lists the rulings, the row 225 contract and what is left.
Preserve the draft for inspection under sage-3113. Tests and mutants have not run. Old-test adaptations approved in mos-1316 and mos-1317 are recorded in OLD-TEST-CHANGES.md.
Console granted-user sign-in, a user-cli transport per session, the
per-request grant re-read, the owner-only gate and user page, the notice,
the hub label and peer links, accessContextFor peers, and the bus boot
access wiring (sage-3142). Tests G1-G8 and B1-B3 are written and not yet
run; runs wait for Sage's CLEAR. Choices C1-C9 in
agents/launchpad/work/queue-294/BUILD.md.
The section "recover() change, for a design read" covers three things, with
file:line against aca16404c. Every leftover is still bound and ended as
host-lost, and a survivor only refuses legacy-run-live while it lives. The
5 s wait applies only in the bwrap kill branch. No old test's expected value
changes. The fallback is to revert to the base recover() and leave the
refusal untested. The survivor log line now names the outer and runner pids
so an operator can clear it, and the new test's log assertion matches.
recover() kept a survivor only when a bwrap outer pid outlived SIGKILL, so
the Q2 refusal (BUILD.md:177-179, t1-sessions.md:109) had no test. A leftover
whose runner still ran after its outer pid was gone was ended and dropped.
Now recover() waits on the outer pid and the runner, keeps any leftover where
either still runs, and logs that it still runs. check() reads only the
survivors that still run.
session-launch.test.mjs adds a test where a sessionless leftover's runner is
a sleep child and its outer pid is gone. It asserts the legacy-run-live
refusal with no launch and no session workspace, then one launch once the
child exits. BUILD.md adds mutants M10-M12 and replaces the "no test" note.
threadsState gives one row per session with `session` and `legacy`; threadIdle
idles a run against its bound session. Each session gets its own store
(threads/<b>/<t>/sessions/<s>/, or the thread's old store for a legacy-3l
session) and its own workspace (session-workspaces/<b>/<i>/<s>/), held by an
O_EXCL <ws>.lock from before the clones to the run's proven exit. A legacy
session's workspace binds in-sandbox at the old instance path. sessions.json
is v2 and reads v1. New tests: cli session-launch.test.mjs, seat
session-workspace.test.mjs. Not yet run: tests wait for Sage's CLEAR.
Two old assertions change as exact updates:
- mos-1285: end-launch.test.mjs threadsState deepEqual. The old row shape was
{ thread: 'th-1', instance: 'coder', pending: 0, unread: 0, lastMessage: null,
lastOpen: '2026-10-15T00:00:01.000Z', lastClaim: null, holder: null }; the
row keeps every key and value and adds session: 'th-1', legacy: true.
- mos-1289: thread-launch.test.mjs:182, old line
`const store = join(f.dataRoot, "threads", "acme", A);`
now reads A's default session id from threadsState's `session` key; :183-185
unchanged; one added assert that threads/acme/<A>/session is absent.
Gitea grant executor (steps 0-8, settle, restart, revoke and fire, sweep,
status), the grants.* verbs and mosaic grants, the 3j-3k migration with
gitea_users and gitea_grants, and the section 9 tests with a fake Gitea and
a scratch gitea/gitea:1.27.1 X-G3 test. Build notes in
agents/megavolt/work/queue-236/BUILD.md.