Merge origin/main into docs/tess-ledger-sync-m1
Some checks failed
ci/woodpecker/pr/ci Pipeline was canceled

Resolve tracking-doc divergence for the M4-sync PR (#741):
- TASKS.md: keep the sole-writer ledger (strict superset — every row
  equal-or-more-advanced than main, plus the M4-W running log).
- VERIFICATION-MATRIX.md: take main's newer baseline (evolved AC-TESS-04
  native-port handoff / M4-001+M4-V gate) and re-apply the AC-TESS-05
  TESS-MEM-001 operator-memory reachability mapping on top.
- MISSION-MANIFEST.md: M4 in-progress (auto-merged).
M4 remains in-progress/gate-pending — M4-V has NOT passed (2 gate FAILs;
wave-2 linchpin #740 in review). No source changes; command-authz untouched.
This commit is contained in:
Jarvis
2026-07-13 09:37:03 -05:00
89 changed files with 24084 additions and 53 deletions

View File

@@ -41,7 +41,7 @@ Every call receives an immutable, server-derived actor/tenant/channel scope and
`@mosaicstack/agent` owns the explicit `AgentRuntimeProviderRegistry`; duplicate provider IDs are rejected rather than replaced. Gateway owns `RuntimeProviderService`, which creates a frozen `RuntimeScope` from authenticated `ActorTenantScope` and trusted ingress channel/correlation metadata before every provider call. The service checks the declared provider capability before invoking a side effect and records metadata-only audit events (`providerId`, operation, outcome, actor/tenant/channel, correlation, and resource ID). It never records message bodies, idempotency keys, or approval references.
Termination is fail-closed: a runtime approval verifier must consume a one-time, exact action binding for the provider, session, actor, tenant, channel, and correlation ID before `terminate` reaches a provider. Until the durable verifier is wired, the default verifier denies termination. This internal service introduces no HTTP endpoint; later Discord, CLI, MCP, and provider adapters consume the same gateway boundary.
Termination is fail-closed: a runtime approval verifier consumes a one-time, exact action binding for the provider, session, actor, tenant, channel, and correlation ID before `terminate` reaches a provider. The verifier reuses the Redis-backed `interaction:command-approval:*` store and its expiry/delete-on-consume semantics; it has no parallel approval store. This internal service introduces no HTTP endpoint; later Discord, CLI, MCP, and provider adapters consume the same gateway boundary.
## Authority Model
@@ -52,11 +52,49 @@ Termination is fail-closed: a runtime approval verifier must consume a one-time,
| Destructive, privileged, external/customer-visible action | Human approval + policy | Propose, wait for durable one-time approval, then execute idempotently |
| Provider-specific unsupported action | None | Fail closed; never emulate silently |
### Mos Coordination Boundary
`@mosaicstack/coord` exposes only the transport-neutral `MosCoordinationPort`
verbs `handoff`, `observe`, and `result`. Gateway derives the actor, tenant,
correlation, and interaction-agent identity from authenticated context plus
trusted configuration; callers never provide an orchestration target. It
rejects unconfigured identities, self-delegation, target/correlation drift, and
cross-tenant handoff reads before an adapter call. No dispatch, assignment,
review, merge, or cancellation API exists at this boundary.
M4 uses a deterministic native in-process queue adapter to prove the handoff →
observe → result flow without coupling the contract to tmux. A fleet/tmux
adapter is deferred to the M5 live-deployment seam and must implement the same
port.
## Session and State Model
A Tess session has stable `sessionId`, `tenantId`, `ownerId`, provider/runtime identity, ingress bindings, cursor, checkpoint, inbox/outbox, and idempotency records. Discord and CLI bind to the same authorized session. Ownership is verified server-side on every list/read/attach/send/terminate operation.
Valkey may hold ephemeral coordination state; PostgreSQL is canonical for durable session bindings, approvals, audit, checkpoints, inbox/outbox, and idempotency. Pi session files are replay sources, not cross-agent truth.
Valkey holds the existing short-lived, one-time command-approval records; PostgreSQL is canonical for durable session bindings, checkpoints, inbox/outbox, and idempotency. Pi session files are replay sources, not cross-agent truth.
### M2 Durable Recovery
`@mosaicstack/agent` owns a transport-neutral state machine and `apps/gateway` provides its
PostgreSQL adapter. `interaction_sessions` holds immutable identity; inbox/outbox records use a
per-session unique idempotency key and transition `pending → processing → processed|delivered`.
Checkpoints are immutable history scoped by session and checkpoint ID: the latest checkpoint
supports compaction recovery, while a handoff always resolves the exact checkpoint it references.
Recovery requeues only interrupted inbox work; an ambiguous `processing` outbox record is preserved
until separately authorized reconciliation can establish its external delivery state.
Provider sends travel through the existing `RuntimeProviderService` with the persisted outbox
idempotency key. A normal dispatch claims exactly one outbox record and verifies its stored
correlation and channel against the server-derived request scope; it never requeues or drains
another live record. Inbox/outbox payloads and checkpoint cursor/summary pass through the existing
secret/PII redactor and AES-256-GCM sealing before persistence; decryption occurs only in the
scoped gateway repository path, and runtime audit remains metadata-only.
An external effect cannot share a database transaction. If a process dies after an effect begins
but before its terminal outbox transition, automatic recovery does not replay that ambiguous claim.
It remains `processing` until separately authorized reconciliation can establish delivery state;
completed effects are never redispatched. Operators can therefore restart the gateway/Pi service,
reconstruct the session, and resume pending inbox work without relying on process-local state.
## Transport Strategy
@@ -81,3 +119,5 @@ The provider advertises list, tree, read-only attach, send, and terminate. List/
## Deployment
Tess runs as a rostered, systemd-supervised Pi agent using GPT-5.6 Sol and high reasoning. Secrets are supplied through approved runtime secret mechanisms. Startup fails when required model, gateway identity, Discord binding, or durable-state dependencies are missing. Health reports effective model/reasoning/tool policy without credential material.
The interaction-service identity is provisioning data, not a source identifier: the roster and per-agent environment carry the chosen display/roster name into a generic systemd instance. The service rejects a name mismatch or any drift from its pinned Pi/GPT-5.6 Sol/high/operator-interaction effective policy before launch. Its policy printer exposes only those resolved safe fields.

View File

@@ -0,0 +1,17 @@
# TESS-M4-003 Operator Plugin Sketch
## Memory/retrieval slice — TESS-MEM-001
Introduce a transport-neutral `OperatorMemoryPlugin` in `packages/memory`. The plugin receives a server-derived `{tenantId, ownerId, sessionId}` scope and delegates to a registered `MemoryAdapter`; adapter and namespace are injected configuration, never caller input. Its operations are `capture`, `search`, `recent`, `stats`, and `startupContext`. Results carry configured instance, provenance, and namespace metadata. Capture/redaction occurs before adapter persistence; startup context uses a bounded candidate window ordered so project/flat-file truth takes precedence within returned material.
Registration remains replaceable-adapter based: the existing `registerMemoryAdapter(kind, factory)` / `createMemoryAdapter(config)` seam supplies the injected adapter to `createOperatorMemoryPlugin(config)`. Identity and namespace are configuration data; no interaction-agent name is embedded in keys or defaults.
## Remaining plugin foundations — TESS-PLG-001
- `packages/agent`: capability descriptors for runtime bootstrap, durable inbox/state hooks, and read-only fleet diagnostics. Each capability advertises supported operations and fails closed when absent.
- `packages/mosaic`: a catalog/registration surface for GitOps, fleet diagnostics, runtime bootstrap, Discord, and MCP/skill discovery. Catalog entries describe authority, input schema, and safe/read-only status; they do not invoke provider transports directly.
- Gateway/channel adapters consume these contracts through server-derived actor/tenant context and durable session state, preserving the replaceable-adapter boundary.
## First implementation boundary
The first PR slice should add the operator-memory plugin contract, configuration-injected adapter seam, scope isolation, provenance-bearing retrieval, and tests for namespace isolation plus a differently named configured instance. Durable inbox/outbox remains owned by the existing `DurableSessionCoordinator`; this plugin only supplies bounded context/capture at lifecycle boundaries.

View File

@@ -0,0 +1,83 @@
# TessMos Coordination Contract Sketch
**Task:** TESS-M4-001 · **PRD:** TESS-MOS-001 / AC-TESS-04
## Boundary
Agent identities are deployment data. A configured interaction agent may request
Mos-owned work; the configured orchestration agent owns decomposition, worker
assignment, reviews, and merge decisions. The interaction agent receives a
correlated receipt, read-only activity projection, and terminal result. It has
no dispatch, assignment, review, merge, or cancellation operation.
## `@mosaicstack/coord` interface
```ts
interface CoordinationScope {
readonly actorId: string;
readonly tenantId: string;
readonly correlationId: string;
readonly requesterAgentId: string; // trusted gateway/configuration data
}
interface MosHandoffRequest {
readonly idempotencyKey: string;
readonly summary: string;
readonly context?: string;
readonly missionId?: string;
}
interface MosHandoffReceipt {
readonly handoffId: string;
readonly targetAgentId: string;
readonly status: 'accepted' | 'queued';
readonly correlationId: string;
}
interface MosHandoff {
readonly handoffId: string;
readonly targetAgentId: string;
readonly request: MosHandoffRequest;
readonly scope: CoordinationScope;
}
interface MosCoordinationPort {
handoff(handoff: MosHandoff): Promise<MosHandoffReceipt>;
observe(handoffId: string, scope: CoordinationScope): Promise<CoordinationObservation>;
result(handoffId: string, scope: CoordinationScope): Promise<CoordinationResult>;
}
```
The port deliberately omits generic orchestrator verbs. It is tenant- and
correlation-scoped; its gateway implementation obtains `actorId`, `tenantId`,
and the requester agent from trusted authentication/configuration only.
## Enforcement point
`apps/gateway` owns a `MosCoordinationService` boundary that compares the
trusted configured requester/target identities and rejects all of the following
before calling a transport: unconfigured requester, self-delegation, target
identity drift, cross-tenant observe/result lookup, and attempts to observe or
receive a result for a handoff outside the originating tenant. The service exposes handoff, observe,
and result only, and delegates delivery to an injected adapter.
M4 ships a native in-process `InMemoryMosCoordinationPort` as the concrete,
deterministic adapter. It preserves the immutable handoff ID, tenant, requester
identity, and correlation ID while demonstrating the handoff → observe → result
round trip. It is a queue/port adapter, not a Mos-side consumer.
A future fleet/tmux adapter is a documented M5 deployment seam and must
implement the same `MosCoordinationPort`; no channel client or interaction
runtime calls a transport directly.
## Required tests
1. A configured non-default interaction identity can hand off work to a
configured non-default orchestration identity and receive its result.
2. The gateway passes only server-derived scope/identity to the adapter.
3. Self-targeting, target drift, and cross-tenant observe/result all fail closed
without invoking the adapter.
4. The exported public contract has no worker-dispatch, assignment, review,
merge, or cancellation capability.
5. The native adapter round-trips queued work, activity, and a host-recorded
terminal result without a live fleet dependency.

View File

@@ -5,7 +5,7 @@
| AC-TESS-01 | TESS-PI-001, TESS-DSC-001, TESS-CLI-001 | Discord/CLI same-session integration and streaming E2E | M3-V |
| AC-TESS-02 | TESS-ARP-001, TESS-CLI-001, TESS-FLT-001 | CLI contract tests for status/sessions/tree/attach/send/stop, typed denial/error snapshots | M3-V |
| AC-TESS-03 | TESS-PI-001, TESS-OBS-001 | Clean service launch; status asserts GPT-5.6 Sol, high reasoning and effective tool policy with secret canaries absent | M2-V, M3-V |
| AC-TESS-04 | TESS-MOS-001, TESS-FLT-001 | Authority E2E: coding request creates Mos handoff; safe status runs in Tess; no competing worker claim | M4-V |
| AC-TESS-04 | TESS-MOS-001, TESS-FLT-001 | M4 contract/gateway native-port handoff → observe → result round trip; configurable identity, target-drift and tenant-denial tests; M4-V fleet authority qualification | M4-001, M4-V |
| AC-TESS-05 | TESS-HRM-001, TESS-MEM-001 | Hermes capability contract suite: sessions/stream/send/tree plus Kanban/skills/memory/tools/cron supported-or-denied matrix; operator-memory plugin (TESS-MEM-001) reachable end-to-end — env-configured plugin registered + AgentService session-bound server-derived {tenantId,ownerId,sessionId} scoped search/capture, cross-tenant reuse denied before plugin call (M4-W-001 spine: #736 plugin + #739 consumer) | M4-V |
| AC-TESS-06 | TESS-STA-001, TESS-SEC-008 | Kill/restart/compaction fault injection across inbox/outbox/checkpoint transitions; duplicate side-effect detector | M2-V, M5-V |
| AC-TESS-07 | TESS-SEC-001..009 | Threat-model abuse suite: authz, tenant isolation, forged identity/approval, injection, redaction, transport identity, GC scope | M1-V, M3-V, M5-V |

View File

@@ -0,0 +1,19 @@
# TESS-HRM-001 — Hermes runtime adapter boundary
## Normalized provider surface
`HermesRuntimeProvider` implements the existing Mosaic-owned `AgentRuntimeProvider` unchanged. Its public surface is therefore `capabilities`, `health`, session list/tree, stream, send, attach/detach, and terminate, accepting only `RuntimeScope`, `RuntimeMessage`, `RuntimeSession`, `RuntimeStreamEvent`, and other types from `@mosaicstack/types`. Provider id is `runtime.hermes`.
The provider receives a narrow injected `HermesRuntimeTransport`, whose method names and inputs may represent Hermes API operations but whose return values are explicitly private `HermesLegacy*` types defined only in `packages/agent/src/hermes-runtime-provider.ts`. Mapping functions convert those private values to Mosaic sessions, state, hierarchy, and stream events. Capability negotiation maps a supplied Hermes feature inventory onto the fixed Mosaic runtime capability vocabulary; no unknown/ambiguous legacy feature is advertised. Unsupported Mosaic operations throw the typed fail-closed `capability_unsupported` provider error before a transport call.
## Boundary line
**Hermes legacy schema ends at `HermesRuntimeTransport` and its private adapter-local `HermesLegacy*` definitions in `packages/agent`.** `packages/types` is never changed to contain a Hermes field, enum, identifier, session shape, status, or capability. `apps/gateway` registers/resolves the provider only through `AgentRuntimeProvider` and receives normalized values only. Identity remains server-derived `RuntimeScope` data and is passed to the injected transport as context, never reconstructed from a legacy response.
## Initial mapping and safety posture
- Hermes conversation/thread identifiers map to opaque Mosaic `RuntimeSession.id`; parent linkage maps only when a known parent exists.
- Hermes status strings map through a closed lookup to `RuntimeSessionState`; unknown statuses become `failed`, never a permissive active state.
- Legacy stream chunks map to `message.delta` / `message.complete`; malformed or unsupported events become a normalized `runtime.error` event.
- Send, attach, and terminate require the normalized capability first. `terminate` continues to be approval-bound by the gateway service; the adapter does not weaken gateway authority.
- Kanban, skills, memory, tools, and cron are capability-inventory entries for this transitional adapter, not additions to the core runtime contract. They are reported as explicitly unsupported until a Mosaic-owned capability contract exists.