diff --git a/BUILD-LOG.md b/BUILD-LOG.md index c93db37bd..73826cfb0 100644 --- a/BUILD-LOG.md +++ b/BUILD-LOG.md @@ -5179,3 +5179,5 @@ Before: managed project/thread verbs had no Console conversation area. After: fi 2026-10-21T06:37:41Z | Darkwing | row 240 #1746 installer I4 build, round 1 in review | Before: root had no host check for the bwrap AppArmor profile, its pins or a boot unit, and stack-upgrade.sh exited 1 args-failed when the args move after A5 failed, while exit 1 means the old copy runs. After: scripts/case1-hostcheck.sh (seven items, --check, --enforce, --upstream), scripts/case1-pins.sh, mosaic-hostcheck.service and 16 tests; the args move failure exits 5 args-failed, documented in TOOLS.md and run sheet section 6 and tested; run sheet section 3 puts the pinned npm on PATH and names the bin/claude.exe --claude path; sections 8 and 10 have precheck lines. Verification: slot run r1 on 47ec9fe2f failed at the singles (the new N1 test's after hook threw ENOENT after the fixture cleanup removed the root); b45852daa drops the hook; r2 on b45852daa green: singles 16/0 and 21/0, c0 plus M1-M8 8/8 killed, cli 639/0, scripts 585/0. Candidate darkwing/row240-r3 ad1b23ab2 on c771a36f4, manifest 573ece95 (9 paths), revs 2694 and 2695, comment 29943. 2026-10-21T16:34:44Z | Huey | Q198/Q199 system-manager design, mos-1183, Vikunja 452 | Before: pinned foundation 6c75887b0 has separate bus, development queue, run evidence, turn/cohort controls and launch/usage paths; the assignment requests a mechanical manager design. After: docs/plans/2026-10-21_q198-system-manager.md proposes admission/cooldown, priority and safe interruption, durable requests, bounded retry/DLQ/replay/rerouting, Console monitoring, optional decision adapters with USD reservations, six ordered slices and three recommended owner decisions. Verification: 26 pinned file:line references resolve, ten-line summary, manual source/contract review, git diff --check and installed queue guard pass. No builds/suites, runtime writes, credential reads, service changes or paid calls. Huey queue next refused the linked worktree, then returned nothing from canonical checkout; direct brief controls this assignment. Gitea issue and queue-row capture are handed to Sage under the no-credential-read/no-queue-write boundary. + +2026-10-21T18:45:47Z | Huey | Q198 system-manager design r2, mos-1194, Vikunja 452 | Before: Scrooge requested changes on add7cb506 for decision-key worker exposure, cap scope and absent sampler ownership. After: distinct MOSAIC_DECISION_OPENROUTER_KEY with S6 sessionEnv canary requirement; exclusive per-instance key with per-key caps and provider limit on every enablement; S2 owns supervisor sampler and waits until after MVP/re-pin. Also records P1 interpretation, missing-confidence fallback and stand-in timeout selection, explains verified Noul spelling, excludes notifier/gateway retry loops with citations, and cites lifecycle revocation requirement. Verification: 30 pinned citation spans resolve, ten-line summary, manual diff/source review and whitespace/queue-guard checks. No builds, suites, live changes, credential reads or paid calls. diff --git a/docs/SESSIONS.md b/docs/SESSIONS.md index 69c83ff96..0c831b609 100644 --- a/docs/SESSIONS.md +++ b/docs/SESSIONS.md @@ -1420,3 +1420,4 @@ are never rewritten or removed; corrections are new entries. 2026-10-21T07:29:23Z | researcher | row 228 (#1729) landed as 86249ac55 (pushed 07:25Z by Sage) | patch-id b6ffe31feb0d matches my r3 candidate cf18c42b9 (checked here against origin/refactor); Sage combined gate with 238: seat 165/0, cli 640/0, scripts 585/0; queue note rev 2725, done rev 2727, #1729 closed comment 29966 (sage-1824); q228r2 worktree removed, branches researcher/row228, -r2 and -r3 stay on origin and locally; packets agents/researcher/work/queue-228 r1 r2 r3 uncommitted 2026-10-21T15:19:14Z | Sage (Opus 5.5, 1ef1e4f8) | MVP push 10-21 afternoon: rows 249, 197 proof 3/4, 222 singles, 66 r4d, queue-commit | 249 landed 9de5a57ab (+7b9737953 DEFERRED N1, #1751 closed, Vikunja 445 c442); 197 proof 3 rc=1 on a driver defect, Herb's fix a5b636750 to Webby, proof 4 set up in sage-r197p4; 222 singles 34/34 and 5 mutants killed (sage-2028); 66 round 4 in review (82c830779, c30083/30084); queue revs 2642-2904 committed 0636721e6 2026-10-21T16:34:44Z | Huey (gpt-6.1-sol) | mos-1183, Q198/Q199 system-manager design, Vikunja 452, huey/system-manager-design on 6c75887b0 | design and six proposed slices documented; pinned citations and docs checks pass; no build, suite, live action or paid call; Gitea/queue capture remains Sage-owned +2026-10-21T18:45:47Z | Huey (gpt-6.1-sol) | mos-1194, Q198 design r2, scrooge-0001 findings 1–8, Vikunja 452 | all findings addressed in design and slice acceptance criteria; 30 citation references checked, no suites/live changes/paid calls; Mos routes r2 back to Scrooge diff --git a/docs/plans/2026-10-21_q198-system-manager.md b/docs/plans/2026-10-21_q198-system-manager.md index 5ed2d2e82..f7b032b52 100644 --- a/docs/plans/2026-10-21_q198-system-manager.md +++ b/docs/plans/2026-10-21_q198-system-manager.md @@ -12,11 +12,12 @@ No live trial, key installation or runtime change is authorized by this design. MVP work (Vikunja 414 and 416) keeps first claim on Sage’s gate. Brief: mos-1183, DECISIONS Q198/Q199, Vikunja **452**. Owner: Huey. Design only. +Revision **r2**, mos-1194, addresses Scrooge’s review of `add7cb506` (scrooge-0001). All defaults below are proposals, not measured safe operating limits or new authority. ## 1. Existing pieces and reuse -Code citations in this section mean **commit `6c75887b0`**, even when a later branch +Code citations throughout this document mean **commit `6c75887b0`**, even when a later branch changes the line. Inspect with `git show 6c75887b0:PATH | nl -ba`. The gate candidate is explicitly cited at `d2de56bd2` instead. Plans establish intent, not running behavior. @@ -39,7 +40,8 @@ Row 194’s brief requires per-agent vetoes, RBAC and kill-switch checks (`docs/plans/2026-10-20_agent-lifecycle.md:27-35`). At this base, launch revoke/restore are human-only broker operations (`packages/bus/src/broker.mjs:3189-3203`). Treat the briefs as integration contracts, not evidence those whole features landed. The manager -must defer to their final reviewed implementations, including credential revocation. +must defer to their final reviewed implementations, including the brief’s credential +revocation requirement (`docs/plans/2026-10-20_agent-lifecycle.md:41-45`). **F12 Gate lanes are a separate owner.** On **`d2de56bd2`**, grants, private roots, port bands, quarantined receipts and image locking are described at @@ -99,6 +101,9 @@ cross-UID arbitration needs a separately approved host-service boundary. No proc name scan grants cancellation authority over another user or instance. Configuration extends the instance’s one system config through the normal reviewed schema/bootstrap path, never a second configuration file or automatic rewrite of an existing config. +Decision spending is separately scoped per exclusive key, not per host or shared +account. D11 requires one dedicated decision key per instance. Shared keys are unsupported +until a shared ledger and its authority boundary receive separate review. ## 3. Classes and interrupt semantics @@ -109,6 +114,12 @@ path, never a second configuration file or automatic rewrite of an existing conf | P2 normal | User/agent turns, ordinary task dispatch | FIFO within tenant, fair rotation across tenants. May request cooperative yield from background work. User text saying “urgent” does not confer system authority. | | P3 background | Builds, indexing, maintenance, optional evaluations, granted test gates | Lowest resource admission priority. A granted gate retains Sage’s independent exclusivity and evidence rules. | +The P1 capacity/authorization hold narrows Jason’s Q198 “take precedent” direction: +system recovery gets priority over eligible normal work, but heavy recovery cannot +bypass authorization, kill state or hard capacity. This is a proposed safety restriction, +not a claim that Jason already approved that exception. Bounded health and reconciliation +retain reserved capacity. Mos should flag this interpretation when seeking design approval. + | Work | What interrupt means | Hard-stop boundary | | --- | --- | --- | | Agent turn | Fence new dispatch, ask its controller to abort, reconcile queued input and effects (F5). | Escalate only through an already-authorized force stop/kill path. Uncertain proofs retain the reservation (F6). No automatic reissue of the prompt. | @@ -176,6 +187,12 @@ Re-enter admission on every attempt. Restarts preserve counters/deadlines. Proxy retries must fit a declared per-attempt budget. If that budget is unknown, do not layer automatic manager retries over the proxy. Max one route change within the three attempts. +D6 covers managed work requests only. Existing notifier delivery backoff +(`packages/cli/src/notifier.mjs:33-34,257-315`) and Discord gateway reconnect backoff +(`packages/discord/src/gateway.mjs:40,120-133`) stay out of scope and keep their own +owners. Do not wrap either loop in manager retries or count reconnects as work attempts. +Any later consolidation needs its own design and acceptance tests. + | Outcome | Action | | --- | --- | | Connection refused before send, explicit 429/503 with no accepted work, safe read failure | Bounded retry/cooldown when adapter proves eligibility. | @@ -205,7 +222,15 @@ is separate from enabling the decision hook. F10’s preflight fallback remains ## 6. Monitoring and Console -**D9 Measurements.** Pressure samples and freshness, active/reserved work, ownership +**D9 Sampler ownership.** S2’s implementer owns the live sampler inside the mechanical +supervisor process proposed in D1, running in monitor-only mode before admission lands. +That process samples every 2 seconds and supplies timestamped local snapshots through +the Console’s authenticated bus read transport. The Console does not read `/proc` +itself. Process death/stale samples show unknown. Request/provider fields show unavailable +until their adapters land. Starting this process and updating the live Console require +an approved re-pin window after MVP. No sampler is started by this design work. + +**Measurements.** Pressure samples and freshness, active/reserved work, ownership uncertainty, queue depth/oldest wait by class, hold time/reason, admission/turn latency, retry counts, DLQ growth, route failures, provider cooldown/reset, stop proof state, manager heartbeat and decision-model timeouts/spend/unknown charges. Store bounded @@ -236,21 +261,33 @@ other decision models without exposing their wire format to the scheduler. Enabling paid assistance is a user setting, recommended in setup with its price/cap shown. Pin **`typesafe/jev-1.14`** as the recommended initial model, never a moving “latest” alias. Its [OpenRouter guide](https://openrouter.ai/docs/guides/community/jev) -documents typed choice/noul/score answers with probabilities and +documents **Choice** (select an option), **Noul** (probability of yes) and **Score** +(ordered scale) primitives with probabilities, and `POST https://openrouter.ai/api/alpha/decisions`. The [model page](https://openrouter.ai/typesafe/jev-1.14) lists $0.042 per million input tokens, free output and 262,144 context tokens (verified public documentation 2026-10-21, not a live call or price guarantee). Use choice for route selection. Do not send images or use the large context window. Other decision models need their own adapter contract and calibrated confidence tests. -Hard timeout **500 ms**, max one in-flight decision per instance, no decision-call -retry. Timeout, invalid answer, stale snapshot, low confidence (<0.8 initially), cost -uncertainty or network failure immediately selects rules. Discard late answers for +Initial timeout candidate **500 ms**, max one in-flight decision per instance, no +decision-call retry. S6 measures latency and timeout/fallback rates on delayed stand-ins, +then records the selected timeout and evidence before acceptance. Stand-ins verify the +local budget, not real provider latency. Timeout, invalid answer, stale snapshot, +missing/non-finite/out-of-range confidence, low confidence (<0.8 initially), cost +uncertainty or network failure immediately selects rules. An adapter without a calibrated +confidence value therefore uses rules. Discard late answers for routing, but still account for their charge. The hook cannot authorize work, choose P0/P1 status, change thresholds, clear a kill, replay effects, or choose outside the eligible set. Recheck eligibility after it returns. Never call it for safety actions. -**D11 Cost.** Proposed opt-in defaults: **$0.10/day and $1/month**, both enforced. +**D11 Cost scope.** Proposed opt-in defaults: **$0.10/day and $1/month per dedicated +decision key**, both enforced by its owning instance’s durable ledger. Each instance +must use a separately provisioned key used only for that instance’s decisions, with a +non-secret provider key ID bound to the instance in the approved setup record. Reject +enablement if exclusive ownership cannot be established. Do not reuse a worker key or +share the decision key across instances or other clients. Shared-key operation is held +until a shared ledger exists. These are not account-wide caps: N enabled instances +with N keys permit N times the defaults. Setup shows that combined authorized budget. Use integer currency units/decimal parsing, never binary-float threshold comparisons. Before send, durably reserve an upper bound from a pinned price ceiling and a bounded serialized request (≤4 KiB, verified worst-case tokens and all billable fields). Count @@ -259,8 +296,10 @@ Reconcile once per provider request ID using **`usage.cost`** in USD, as documen the [Jev guide](https://openrouter.ai/docs/guides/community/jev). Keep reservations for timeouts/crashes until settled. Missing/invalid cost, price above ceiling, or a charge above reservation disables paid decisions and alerts. Never interpret absent cost as -zero. A provider-enforced spend limit is also required for an approved live trial: -local accounting alone cannot guarantee a hard ceiling against upstream misbilling. +zero. A provider-enforced limit bound to that dedicated key is required for **every +enablement**, including trials, in addition to the local daily/monthly caps. If the +provider cannot enforce the approved key budget, keep paid decisions disabled. Local +accounting alone cannot guarantee a hard ceiling against upstream misbilling. Day/month windows use UTC. No cap rollover drops an unresolved reservation. Configure caps before enabling. **D12 Data and key.** Send only enum work type/class, numeric resource estimates, @@ -272,9 +311,14 @@ and a tested schema/redaction rule. Log sanitized decision inputs/output IDs and never wire headers. Model output is untrusted data. Proposed slot reference only: `/secrets/openrouter-decision.env`, -name **`OPENROUTER_API_KEY`**. This is not an existing slot claim. Jason places the value -only after live-trial approval. Runtime mounts/injects it read-only into the decision -adapter, never the model state or worker. No management key access. A direct Decisions +name **`MOSAIC_DECISION_OPENROUTER_KEY`**. This is not an existing slot claim. The +ordinary `OPENROUTER_API_KEY` is in `ENV_ALLOW` and `sessionEnv` copies allowed variables +(`packages/seat/src/session.mjs:83-99`), so it must never hold the decision key. Jason +places the dedicated value only after live-trial approval. Runtime injects it only into +the decision adapter, never the shared launcher environment, model state or worker. +Do not add the distinct name to the worker allowlist or alias its value to an allowed +provider variable. S6 must prove `sessionEnv` excludes the distinct variable using a +synthetic canary. No management key access. A direct Decisions adapter may be needed unless a stand-in proves the approved proxy supports this API. ## 8. Proposed queue rows, smallest first @@ -286,11 +330,11 @@ authorized here. Vikunja 450/451 and MVP 414/416 retain their existing order/aut | Ref/order | Slice and dependency | Acceptance evidence | Before 10-27? | | --- | --- | --- | --- | | S1 | Pressure parser and pure rules evaluator, no live enforcement | Synthetic load/memory/PSI/missing-signal cases, exact hold/release thresholds, fake-clock hysteresis, effective CPU/memory limit cases. No builds or real pressure generation. | Candidate could land if Sage has spare review/gate capacity. Never displace MVP. | -| S2 | Read-only Console System status, after S1 | Fixture HTTP responses for healthy/held/stale/unknown and auth scoping. No writer, no secret or command-line fields. | Could land with spare capacity only. | +| S2 | Live sampler in the mechanical supervisor process (monitor-only), plus read-only Console System status, after S1. S2 implementer owns process lifecycle and snapshot transport (D9). | Fixture sampler feeds timestamped Console responses for healthy/held/stale/unknown. Process death, unavailable adapters and auth scoping tested. No admission writer, secrets or command-line fields. | After MVP. Live sampler/Console activation needs an approved re-pin window. | | S3 | Request journal/admission, after S1 and final kill/lifecycle contracts | Migration/rollback compatibility, duplicate-key conflict, crash before/after spawn, two dispatchers, generation fencing, queue limits/expiry, provider cooldown, fairness under sustained traffic, kill-at-launch race, instance isolation. | After MVP preferred. Schema and dispatch integration need a full owned gate. | | S4 | Cooperative interrupts and capacity ownership, after S3 and adopted gate lanes | Agent abort proof vs uncertain, test-step cancellation/quarantine, owned build cleanup, PID reuse, remote tool unknown outcome, emergency request during full backlog. No gate grant synthesized. | After MVP. | | S5 | Retry/DLQ/replay and permitted reroutes, after S3/S4 | Fake provider failures with exact total-attempt/time bounds, restart during backoff, Retry-After, unknown proxy budget, partial-stream/write no replay, authorized replay lineage, incompatible-route refusal. | After MVP. | -| S6 | Decision hook, USD ledger and setup, after S5 | Stand-in typed responses, late/invalid/low-confidence answers, unapproved action, snapshot race, redaction canaries, concurrent cap reservations, missing/duplicate cost, crash and day rollover. Network disabled by default. | Fixture implementation may proceed later. No paid trial before explicit approval. | +| S6 | Decision hook, per-exclusive-key USD ledger and setup, after S5 | Stand-in typed responses, late/invalid/missing/low-confidence answers, unapproved action, snapshot race and redaction canaries. Measure timeout rates and choose the timeout from stand-in results. Verify `sessionEnv` drops `MOSAIC_DECISION_OPENROUTER_KEY`. Test exclusive key binding, reject shared keys/missing provider limit, independent-key budget totals, concurrent reservations, missing/duplicate cost, crash and day rollover. Network disabled by default. | Fixture implementation may proceed later. No paid trial before explicit approval. | Each slice gets independent review and tests that kill a mutation of its central invariant. Sage chooses package/full-suite gates appropriate to the final diff. @@ -303,15 +347,21 @@ bounded synthetic pressure. No load experiment on the shared development host. - **Q1 Initial authority:** should the manager ever force-stop background work just for load? **Recommend no.** Cooperative yield for load, hard stop only through an already-authorized safety/explicit stop. Broader authority needs a separate decision. -- **Q2 Trial spend:** accept $0.10/day, $1/month and a provider-side ceiling for the - first trial? **Recommend yes**, with rules staying default until Jason enables it - and installs the slot. Q199 provides readiness, not approval to spend now. +- **Q2 Trial spend:** accept $0.10/day and $1/month per exclusive instance key, with a + provider-side key ceiling for every enablement? **Recommend yes**, with the combined + account budget shown and rules staying default until Jason enables it and installs + the slot. Q199 provides readiness, not approval to spend now. - **Q3 Reroute consent:** may setup authorize a named alternative model/provider list? **Recommend yes**, per role and privacy requirement. Empty list means hold/fail visibly instead of silently changing providers or model quality. ## Verification and handoff +r2 addresses Scrooge findings 1–8: distinct key isolation, exclusive-key cap scope, +sampler/process ownership and post-MVP re-pin, P1 interpretation, missing-confidence +fallback and measured timeout selection, verified Noul spelling, retry scope exclusions, +and a citation for the lifecycle brief’s revocation requirement. + This document was checked against the pinned source and public documentation only. No build, suite, live bus write, service action, proxy inspection or paid call was performed. The canonical `scripts/mosaic queue next huey` returned `nothing`.