From 3f69d45334917de72c09f3be7643225155ebdb98 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Mon, 22 Jun 2026 21:08:41 +0000 Subject: [PATCH] docs(fleet): consolidate north-star doctrine (budget + control plane + identity) (#629) Co-authored-by: Jason Woltje Co-committed-by: Jason Woltje --- docs/TASKS.md | 4 + docs/fleet/north-star.md | 255 ++++++++++++++++++++++-- docs/scratchpads/north-star-doctrine.md | 19 ++ 3 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 docs/scratchpads/north-star-doctrine.md diff --git a/docs/TASKS.md b/docs/TASKS.md index 7309af8..15ac354 100644 --- a/docs/TASKS.md +++ b/docs/TASKS.md @@ -78,3 +78,7 @@ Active workstream is **W1 — Federation v1**. Workers should: ## Fleet stand-up fixes — model_hint→--model + socket-default trap (#626) — feat/fleet-standup-fixes - Status: implemented + tested. FIX1 model_hint→MOSAIC_AGENT_MODEL→--model. FIX2 absent socket = default tmux socket (no -L) across parse/spawn/systemd-unit/observe (socketArgs helper, bare-empty shellEnvValue, conditional -L). 158 fleet tests green; shipped presets unaffected (explicit socket_name). Detail: scratchpads/fleet-standup-fixes.md. + +## north-star doctrine consolidation — doc PR — feat/north-star-doctrine + +- Status: applied Mos's consolidated merge-map to docs/fleet/north-star.md (budget governance + control plane/central register + 200k cap + delegation + unified-identity Fleet + role-based naming + tmux security + drift re-captures). Doctrine only; #622/#623/#625/#628 out-of-scope. Conflict checklist green. Detail: scratchpads/north-star-doctrine.md. diff --git a/docs/fleet/north-star.md b/docs/fleet/north-star.md index 6d4a253..642036e 100644 --- a/docs/fleet/north-star.md +++ b/docs/fleet/north-star.md @@ -55,14 +55,22 @@ The Fleet inherits — does not re-invent — the MVP's hard requirements: One **definition** is the source of truth; the **session** is how it runs. -| Layer | Owner | Phase-2 reality | Destination | -| -------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------- | -| **Definition + identity + auth** | gateway / `mosaic-as` (scoped tokens, #541) | `roster.yaml` (tenant-tagged) | one definition; `mosaic agent --new` materializes it | -| **Tenancy boundary** | **Linux uid per tenant** (linger, own `systemd --user`, own socket, own `~/.config/mosaic`) | one tenant: `jarvis` = tenant zero | uid-per-tenant; federation aggregates across hosts | -| **Runtime** | per-tenant tmux session on isolated socket | dogfood stub sessions (live now on `mosaic-factory`) | claude/codex/pi/opencode TUIs | -| **Liveness** | **heartbeat protocol** every runtime answers | protocol defined + dogfood stub answers it | all runtimes answer; "healthy" ≠ "pane alive" | -| **Observation** | read-only `watch` (native tmux) + `pipe-pane` stream | CLI `watch`/`ps`; explicit opt-in `attach` for control | + auth-gated webUI streams | -| **Control plane** | **federation** across hosts × tenants | records already carry `tenant_id` + `host` | federated gateways expose fleet state; webUI in Phase 5 | +| Layer | Owner | Phase-2 reality | Destination | +| -------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | +| **Definition + identity + auth** | gateway / `mosaic-as` (scoped tokens, #541) | `roster.yaml` (tenant-tagged) | one definition; `mosaic agent --new` materializes it | +| **Tenancy boundary** | **Linux uid per tenant** (linger, own `systemd --user`, own socket, own `~/.config/mosaic`) | one tenant: `jarvis` = tenant zero | uid-per-tenant; federation aggregates across hosts | +| **Runtime** | per-tenant tmux session on isolated socket | dogfood stub sessions (live now on `mosaic-factory`) | claude/codex/pi/opencode TUIs | +| **Liveness** | **heartbeat protocol** every runtime answers | protocol defined + dogfood stub answers it | all runtimes answer; "healthy" ≠ "pane alive" | +| **Observation** | read-only `watch` (native tmux) + `pipe-pane` stream | CLI `watch`/`ps`; explicit opt-in `attach` for control | + auth-gated webUI streams | +| **Control plane** | **federation** across hosts × tenants | records already carry `tenant_id` + `host` | federated gateways expose fleet state; webUI in Phase 5 | +| **Central register** | Postgres `fleet` schema (gateway instance); access via gateway API only | _none in PoC_ (files + `roster.yaml`) | agents, missions, tasks, heartbeats, spend — single network-accessible SSOT; docs = generated projections | +| **Budget / spend governance** | **per-tenant budget policy** ingested by the orchestrator + routing layer | none today (spend is unmetered) | usage-vs-limit feedback ingested; spend auto-paced to the limit window; per-provider/per-account/concurrency/API-$ budgets enforced | + +> **PoC socket hygiene:** the PoC fleet runs on the **default tmux socket** (no `-L`). +> The named production-isolation socket is **`mosaic-fleet`** (matches the product brand); +> an absent roster `socket_name` means the default socket everywhere (spawn, `fleet ps`, +> onboarding cheat-sheet). The legacy dogfood canary still runs on the old `mosaic-factory` +> socket pending migration. ## Operating model (inherited, not reinvented) @@ -113,6 +121,67 @@ Every artifact, starting Phase 2, MUST: 3. Define **healthy = answered a heartbeat within N seconds**, never just "pane alive". 4. Make **observation read-only by default**; control is an explicit, separate, opt-in verb. +> **OPS INVARIANT — runtime agents need a real TTY.** Claude/Codex/pi/opencode agents +> cannot be bare-launched from a systemd `ExecStart`; a durable harness with a real PTY is +> required. This is **why `start-agent-session.sh` launches into tmux** and uses a +> `MOSAIC_AGENT_COMMAND` override rather than running the runtime directly under systemd. + +## Budget & token governance (first-class fleet concern) + +Spend is a fleet-level resource, not a per-agent afterthought. The fleet treats token +and API-dollar budget the way it treats liveness: a signal every runtime exposes and the +control plane is accountable for. This rides the same primitives as everything else — +`tenant_id` + `host` on every spend record, **read-only metering by default**, and the +**federation** layer as the cross-host aggregation point (W1) — so budgeting is zero-foreclosure +from day one even while one tenant exists. + +**Two spend regimes, one policy surface:** + +| Regime | Feedback signal | Fleet obligation | +| ------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | +| **OAuth-subscription runtimes** (Claude sub, Codex sub) | runtime exposes **current-usage-vs-limit** within a rolling limit window | **ingest** the signal per sub-account; **auto-pace** agentic spend so the window is not exhausted early | +| **API-token runtimes** (metered per token) | provider billing / token counts | enforce **hard $-spend ceilings**; on breach, **downgrade → queue → refuse** (below) | + +**Auto-pacing law (OAuth subs) — EVEN-SPREAD default (Jason override, 2026-06-22):** the fleet +paces agentic token spend to consume the limit window **evenly over remaining time**: +target rate = _(remaining usage available)_ ÷ _(remaining time in the window)_. Example: 100% of +a 7-day window = **~14.285%/day**; the system tracks current usage and continuously re-splits the +remainder evenly to hold pace. **Anticipated token-spend-per-task is the budgeting informant** — +tasks are scheduled against the daily pace, not run until the quota is gone. Rationale: spreading +delivery evenly beats rapidly exhausting usage and losing **multiple days of momentum**. +**Rapid pacing / overspend requires EXPLICIT user authorization;** absent it, even-spread holds. +Pacing is a control-plane decision, surfaced read-only before it throttles a lane. + +**Hard-cap breach behavior (ladder):** when a budget ceiling is hit mid-work, the fleet +**downgrades first** (opus → sonnet → haiku, then Claude → Codex), **queues** the lane at the +cheapest floor until the window resets, and **refuses** only as a last resort. Refusal is never +the first response to a breach. + +**Spend accounting, learning & telemetry:** + +- **Multi-subscription auto-routing:** a tenant with multiple subscriptions may let the fleet + **auto-route work to the account with the most available usage** (within budget policy). +- **Historical spend learning:** every task's token spend is **recorded**; historical data + continuously updates known **spend-per-task**, **typical daily spend**, and projections — so + estimates self-correct and pacing stays on target. +- **Projected + actual spend on artifacts (Mosaic Stack mandate):** PRDs, missions, and task + decomposition **MUST note projected AND actual token spend** — a Mosaic Stack process standard + (template-level), tracked separately as **#622**. +- **Anonymized telemetry → mosaicstack.dev:** spend data is reported (anonymous) to the + mosaicstack.dev telemetry endpoint so other agents/fleets budget and optimize from real, + anonymized data. Product workstream, tracked separately as **#623**. + +**User-settable budgets (the policy surface).** A tenant operator can set budgets for every +configured **provider** (per-provider ceilings), the **account-to-task mapping**, the **agentic +routing flow**, **concurrency** (the spend multiplier), and **hard API-token $-limits**. Budgets +are enforced at the orchestrator + routing boundary, not inside individual workers (a worker never +decides its own budget — see delegation discipline). + +**Budget CLI UX (#558):** `mosaic budget set --reset-at` sets the window reset; reset-datetimes +carry **confidence tags** (`user` / `provider` / `estimated` / `unknown`); and **urgency/criticality +is a dispatch-gate modifier** — high-urgency work may override even-spread pacing **within +authorization**. (Also feeds the budgeting workstream, not only this doc.) + ## Observation model | Verb | Behavior | @@ -127,15 +196,83 @@ Every artifact, starting Phase 2, MUST: > (blank for full-screen TUIs), and `attach` is read-write + resizes the session. The > verbs above restore "join and observe" safely. +## Control plane & central register + +### Why the register must be Postgres + +The fleet is multi-host (w-jarvis + dragon-lin + future). A SQLite file is a local +file — it is not a network service and cannot be shared across hosts. Beyond topology, +Postgres MVCC eliminates the concurrent-writer corruption class Hermes hit with SQLite +under multi-agent access. + +Access is exclusively through the **gateway API** (`apps/gateway` — typed, auth-gated, +scoped tokens). No agent or dispatcher pane ever holds a raw DB credential; a +compromised pane cannot corrupt or exfiltrate the register. + +### Architecture (layers) + +| Layer | Responsibility | Implementation | +| ---------------------- | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Register** | Source of truth: agents, missions, tasks, heartbeats, spend | Postgres `fleet` schema — existing stack instance (`@mosaicstack/db`) | +| **Access** | Typed, auth-gated API | Gateway `fleet/*` routes | +| **Dispatcher** | Brief classification, BOD review, planning/coding/review/test/deploy sequencing + gates → fleet task dispatch | **forge pipeline engine** (`runPipeline`/`resumePipeline`, brief classifier, BOD) **+ thin `forge-exec` adapter → `agent-send.sh`**; NOT a new daemon — forge is reused, only stage→agent dispatch is new | +| **Orchestrator (Mos)** | Goals, missions, judgment, user/PA interface | Context-light; sets intent → re-engages only for decisions | + +### Dispatcher = forge (reuse, do not rebuild) + +The dispatcher is **not new work**: it is `@mosaicstack/forge`, a fully-implemented +software-factory pipeline engine (brief → Board-of-Directors review → 3 planning stages → +coding → review/remediation → testing → deploy). Forge already provides +`runPipeline`/`resumePipeline`, a brief classifier, and a BOD persona loader, so the fleet +does **not** re-implement sequencing, gate logic, or brief classification. The only new +fleet-owned code is a thin **`forge-exec` TaskExecutor adapter** (`ForgeTask` → +`agent-send.sh` to a named agent) — forge's single missing piece — tracked as a Gitea +issue and built post-PoC. The Postgres register backs forge's pipeline state (durable +`resumePipeline`, cross-host) in addition to cross-project missions/tasks/Kanban. The +north-star **'board' role IS forge's Board-of-Directors** — reused from forge, not a new +role implementation. + +### Docs as projections + +`docs/TASKS.md` and `MISSION-MANIFEST.md` are **generated projections** of the DB, +not hand-maintained. The dispatcher (or a scheduled job) renders Markdown from +`fleet.*` tables and commits the output. DB is authoritative; docs are for human +reference. + +### Spend + +`fleet.spend_ledger` records projected and actual token spend per agent/mission/task +(ties to issue #622). The dispatcher enforces budget caps before dispatching. Mos reads +the roll-up via API — no raw DB access, no context-bloating dumps. + +### Federation + +Cross-host fleet state flows through federated gateway queries (existing +`federation_peers` / `federation_grants` machinery). This is the existing north-star +invariant: **control plane rides federation (W1), not a bespoke broker.** No new +broker introduced. + +### Scope + +This is Phase 4–5 of this roadmap, materialized. It MUST NOT block the PoC (which +runs correctly on files + `roster.yaml`). Begin when Phase 2 heartbeat protocol is +stable and concurrent-agent count makes file coordination the bottleneck. + +### Open sub-decision + +Dedicated Postgres **instance** vs. dedicated **schema** in the existing instance. +Recommendation: dedicated schema, existing instance (a migration file, not new infra); +re-evaluate if isolation or write-volume demands it. + ## Phased roadmap -| Phase | Outcome | Status | -| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| 0–1 | tmux PoC, hardening, published CLI v0.0.34 (#565–#568) | ✅ done | -| **2 — Observability** | `fleet ps` (host+tenant aware join), heartbeat protocol + dogfood stub answers it, `agent watch` (read-only), `agent send --verify` receipts | ▶ now | -| 3 — Real runtimes | claude/codex/pi/opencode answer heartbeat; **hybrid lifecycle** (core always-on: **orchestrator + enhancer**; ephemeral workers per lane) | planned | -| 4 — Unified definition | one agent schema in gateway; `mosaic agent --new` → materialized per-tenant session; uid-tenant provisioning | planned | -| 5 — Control plane | federation-backed cross-host × cross-tenant fleet view; **webUI** (surface chosen then) for MVP-X1 parity | planned | +| Phase | Outcome | Status | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| 0–1 | tmux PoC, hardening, published CLI v0.0.34 (#565–#568) | ✅ done | +| **2 — Observability** | `fleet ps` (host+tenant aware join), heartbeat protocol + dogfood stub answers it, `agent watch` (read-only), `agent send --verify` receipts | ▶ now | +| 3 — Real runtimes | claude/codex/pi/opencode answer heartbeat; **hybrid lifecycle** (core always-on: **orchestrator + enhancer**; ephemeral workers per lane) | planned | +| 4 — Unified definition | one agent schema in gateway; `mosaic agent --new` → materialized per-tenant session; uid-tenant provisioning; **`fleet` schema migration + `forge-exec` TaskExecutor adapter (forge → `agent-send.sh`)** | planned | +| 5 — Control plane | federation-backed cross-host × cross-tenant fleet view; **webUI** (surface chosen then) for MVP-X1 parity; **central register live (spend ledger, docs-as-projections, multi-host Kanban)** | planned | ## Decisions of record (2026-06-20, with Jason) @@ -164,6 +301,57 @@ Every artifact, starting Phase 2, MUST: - **Orchestrator chat connector:** the orchestrator is reachable over a user-chosen connector (tmux now; Telegram/Discord/Matrix/Slack configurable). Validated live: **"Mos" orchestrator on Discord** via the Claude Code discord channel plugin (w-jarvis). +- **Session context cap = 200k tokens (GLOBAL to all Claude sessions):** Claude Code sessions are + capped at a **max 200k-token context window**. Long-running sessions extended toward 1M tokens + have proven **worse in practice** (degraded steering, off-plan divergence); 200k is the standard. + **Enforcement split:** the _window_ lives in **`~/.claude/settings.json`** (host-global) as + `"autoCompactWindow": 200000` + `"autoCompactEnabled": true`; the _1M-disable_ lives in **launch + ENV** (`CLAUDE_CODE_DISABLE_1M_CONTEXT=1`, plus `CLAUDE_CODE_AUTO_COMPACT_WINDOW=200000`) wherever + a `[1m]` model can be selected (`mos-claude.service` + the fleet Claude launcher), so every Claude + agent is capped at spawn. (settings = window; env = 1M-disable.) +- **Worker context bound (#8):** workers are kept context-bounded via the **ephemeral-per-lane + lifecycle + native compaction**, not via the 200k knob. The explicit `autoCompactWindow` 200k knob + **stays Claude-specific** — the _principle_ (bounded context) extends to workers, the _knob_ does not. +- **Orchestrator delegation discipline:** the orchestrator **delegates all delivery work** to + subagents / workflows / ultracode / coder agents and confines its own context to \*\*orchestration + - the personal-assistant lane\*\*. Keeping delivery out of the orchestrator's window keeps its + context unpolluted and measurably reduces off-plan divergence. The orchestrator coordinates and + decides; it does not implement. +- **Budget governance is fleet doctrine:** token/API-dollar budgeting is a first-class fleet concern + (see "Budget & token governance"). OAuth-sub usage-vs-limit feedback is ingested per account, spend + is **auto-paced EVEN-SPREAD over remaining time** (rapid/overspend only on explicit authorization), + spend is **tracked historically** to self-correct per-task/daily estimates, multi-sub tenants may + **auto-route by available usage**, and operators set budgets per provider, per account-to-task + mapping, per routing flow, per concurrency level, and as hard API-$ ceilings. +- **Spend accounting is a Mosaic Stack process mandate:** PRDs, missions, and task decomposition + **MUST carry projected + actual token spend**; used locally for pacing and reported as **anonymized + telemetry to mosaicstack.dev**. The template standard (#622) and telemetry product (#623) are + tracked separately. +- **Unified identity = "Fleet" (Jason, 2026-06-22):** the product is **Mosaic Fleet** — one unified + user-facing identity and CLI surface. **forge** is the Fleet's **internal** delivery/orchestration + engine (not a separate product); the control-plane **Postgres register is the Fleet's register**; + workers/runtime are the **Fleet substrate**. **"factory" is RETIRED as a product term** — it was + only ever the software-factory concept (which forge implements) and the old `mosaic-factory` tmux + socket name. The production-isolation socket is now **`mosaic-fleet`** (matches the product brand); + the legacy dogfood canary remains on the old `mosaic-factory` socket pending migration. **Code stays + layered** (forge + fleet + control-plane as internal layers); + only the **identity + CLI surface unify under Fleet.** +- **Role-based session naming (Jason, 2026-06-22):** agent tmux sessions are named by **role** + (`orchestrator`, `enhancer`, `research`, `coder0-0`, …), not by persona. **Persona lives in + `SOUL.md`**; the front-end / Discord presents a **friendly alias** (e.g. "Mos" = the orchestrator's + alias). The session name is the stable addressing handle; the alias is presentation. + +### Control plane & central register + +- **Store:** Postgres (existing stack instance, dedicated `fleet` schema via `@mosaicstack/db`). SQLite rejected: (1) it is a local file — structurally incompatible with a multi-host fleet; (2) concurrent multi-agent writes caused repeated corruption in Hermes. "SQLite + access service" rejected as reinventing a DB server badly; "LLM agent gating DB access" rejected as slow, expensive, and a single point of failure. +- **Access:** gateway API only (`apps/gateway`, `fleet/*` routes). No raw DB credentials in any agent/dispatcher pane — directly mitigates the tmux attack-surface concern. +- **Dispatcher = forge (reuse, not a new build):** the dispatcher IS `@mosaicstack/forge`'s pipeline engine (`runPipeline`/`resumePipeline` + brief classifier + BOD persona loader), a fully-implemented software-factory pipeline (brief → BOD review → 3 planning stages → coding → review/remediation → testing → deploy). We do **not** design/build a new dispatcher and do **not** re-implement sequencing, gate logic, or brief classification. The only new fleet-owned piece is a thin **`forge-exec` TaskExecutor adapter** (suggested package `packages/forge-exec`) mapping a `ForgeTask` → `agent-send.sh` dispatch to a named fleet agent — forge's single missing piece. It is tracked as a Gitea issue and built **post-PoC** (not now). +- **Register backs forge:** the Postgres `fleet` register is genuinely new (neither forge nor the fleet has cross-project state). It BACKS forge's pipeline state (durable `resumePipeline`, cross-host) plus cross-project missions/tasks/Kanban. +- **'board' role = forge BOD:** the north-star role-library 'board' role IS forge's Board-of-Directors — reused, not reinvented. +- **Orchestration vs. dispatch:** Orchestrator (Mos) sets intent and handles judgment; forge works the mechanical pipeline (sequencing, gates, status transitions, spend ledger). LLM escalation reserved for judgment: mission decomposition, re-planning on failure. +- **Spend in the register:** `fleet.spend_ledger` tracks projected vs. actual tokens per agent/mission/task; ties to issue #622. +- **Docs as projections:** `docs/TASKS.md` and `MISSION-MANIFEST.md` become generated exports of the DB, not hand-maintained. +- **Sub-decision pending:** dedicated schema in existing PG instance (recommended) vs. dedicated PG instance. Revisit if isolation or write-volume demands it. ## Future enhancements (north-star, post-MVP — not on the MVP track) @@ -173,6 +361,16 @@ Every artifact, starting Phase 2, MUST: A major enhancement over the current third-party channel plugin; **not required for the MVP**, but a committed north-star target. `ASSUMPTION:` ships as a Mosaic-owned plugin so the fleet controls Discord UX (threads, reactions, attachments, per-thread context) end-to-end. +- **Matrix on a local homeserver — strategic future transport.** **F4 (in progress) IS the Matrix + connector**: an orchestrator chat connector speaking the Matrix client-server API against a + self-hosted homeserver (Conduit default, Synapse alt). Matrix is named here as the strategic + future transport — peer to tmux/Discord, not superseded by them. +- **tmux fleet attack-surface hardening.** Many always-on tmux sessions are an attack surface; + `tmux send-keys` / socket access could enable malicious action against agents directly. + Mitigations to build toward: socket ownership/perms, per-tenant socket isolation (already an + invariant), authenticated `agent-send`, and an audit of who can write to any pane. **Post-MVP + unless a P0 surfaces.** The control-plane register reinforces this (gateway-API access = no raw + DB creds in panes). A not-started risk-assessment + mitigation-plan task rides the Fleet `TASKS.md`. ## Assumptions (veto-able) @@ -184,3 +382,30 @@ Every artifact, starting Phase 2, MUST: - `ASSUMPTION:` Fleet is workstream **W-FLEET** under `mvp-20260312`; a rollup row in `docs/TASKS.md` and a workstream declaration in `MISSION-MANIFEST.md` are proposed to the MVP orchestrator, not written by this workstream. +- `ASSUMPTION:` OAuth-subscription runtimes (Claude sub, Codex sub) expose a machine-readable + current-usage-vs-limit signal the fleet can poll/ingest; if a provider exposes no such signal, + that provider's accounts fall back to API-style hard-ceiling budgeting only (no auto-pacing). +- `ASSUMPTION:` budget policy lives at the orchestrator + routing layer and is surfaced through the + same CLI→TUI→webUI parity (MVP-X1) as the rest of fleet state — not a separate budgeting daemon. +- `ASSUMPTION:` the 200k session cap is enforced by Claude Code settings/env composition (model + variant + `autoCompactWindow`), not by a Mosaic wrapper; a wrapper is the fallback only if the + harness later removes those knobs. +- `ASSUMPTION:` The central register (Postgres `fleet` schema + gateway API + forge as dispatcher) is + the Phase 4–5 control plane, begun after Phase 2 observability is proven. It is a dedicated + **W-FLEET** sub-workstream entry, not a separate mission. The dispatcher is `@mosaicstack/forge` + (reused, not a new daemon); the only new fleet-owned code is the thin **`forge-exec` TaskExecutor + adapter** (suggested package `packages/forge-exec`, `ForgeTask` → `agent-send.sh`), tracked as a + Gitea issue and built post-PoC. + +--- + +> **Release procedure (drift re-capture, 2026-06-22):** `mosaic update` only propagates new fleet +> commands when the **CLI version is bumped** — without a version bump, fleet command changes never +> reach installed hosts. The release/version-bump procedure (bump → publish → `mosaic update` +> [→ `--relaunch`]) must be documented so fleet changes actually land. (Also feeds the budgeting +> workstream.) +> +> **Tracked separately (not in scope for this doc PR):** **#622** PRD/mission/task projected+actual +> spend template standard · **#623** anonymized spend telemetry → mosaicstack.dev (product) · +> **#625** `tenant_id` roster-schema field (multi-tenant; invariant #1 home) · **#628** `forge-exec` +> TaskExecutor adapter (post-PoC). This PR records **doctrine only** — no implementation. diff --git a/docs/scratchpads/north-star-doctrine.md b/docs/scratchpads/north-star-doctrine.md new file mode 100644 index 0000000..e22edc4 --- /dev/null +++ b/docs/scratchpads/north-star-doctrine.md @@ -0,0 +1,19 @@ +# north-star doctrine consolidation (#620-adjacent doc PR) + +- **Branch:** `feat/north-star-doctrine` (off main). Source: Mos's consolidated handoff + 2 drafts (budgeting/200k/delegation + control-plane). ONE conflict-free PR per the merge-map. + +## Applied (merge-map, in order) + +1. Stack table: +2 rows (Central register, Budget/spend governance) after Control plane + PoC-socket-hygiene note. +2. `## Budget & token governance` after Invariants (even-spread pacing [Jason override], hard-cap ladder, multi-sub auto-routing, historical learning, #558 CLI UX) + TTY OPS INVARIANT note. +3. `## Control plane & central register` after Observation model (Postgres fleet schema, gateway-API access, dispatcher = forge pipeline engine + forge-exec adapter [NOT a daemon], register backs forge, board = forge BOD). +4. Phased roadmap Phase 4/5 annotated (fleet schema migration + forge-exec; central register live). +5. Decisions of record (2026-06-22): doctrine §1(c) bullets (200k cap, worker bound #8, delegation, budget, spend mandate, unified identity Fleet, role-based session naming) + control-plane 6c `### Control plane & central register` subgroup. +6. Future enhancements: Matrix-future-transport (#10, F4 IS Matrix) + tmux security hardening (§5). +7. Assumptions: doctrine §1(d) (3) + control-plane 6e (1) + release-procedure note + tracked-separately note. + +## Conflict checklist: all ✓ + +1 Decisions-2026-06-22; order Invariants→Budget→Observation→Control plane→Roadmap; 2 stack rows; even-spread (no opportunistic/HOLD); control-plane UNHELD; forge-exec = tracked #628 post-PoC; §7 drift re-captures all present (#8/#10/#558/TTY/release). + +## Out of scope (cited in doc + PR): #622 (spend template std), #623 (telemetry product), #625 (tenant_id schema), #628 (forge-exec adapter). Doctrine only — no implementation.