Pixir.Subagents.WarmStart (pixir v0.1.14)

Copy Markdown View Source

Warm-start a Delegate child from a named prior Session in the same workspace (#435).

A warm-started child does not open on an empty Log. Its Log is created atomically up front with:

  1. a seq-0 session_fork lineage Event naming the seed Session and inheriting the seed's fork-tree root, so the child joins the seed's Provider cache family (ADR 0020) instead of deriving a fresh s_ segment from its own id;
  2. the seed Session's complete replayable conversational prefix, copied under the existing replay_v1 rules owned by Pixir.Fork (ADR 0024) — full, never a summary and never truncated, because the byte-stable shared prefix is exactly what earns the cache hit;
  3. a runtime-authored lineage boundary marker after that prefix; and
  4. the requested child's live permission_posture immediately after the boundary.

The boundary and posture are runtime artifacts

Both Events are authored here by Pixir in the same Log.create_session/3 event list. No spec field can suppress or move the boundary after the child's first new user message. The boundary is a user_message so it reaches the Provider — a subagent_event would be dropped from the input array. The posture remains durable authorization evidence rather than model conversation.

The fold performed by seed_child_log/3 owns the lineage used in the live posture; an earlier validation snapshot is never authoritative. On cold resume, posture and mutation evidence after the last valid runtime boundary are the live segment. Copied subagent_event and permission_decision Events remain replay evidence, and ordinary Fork replay keeps them, but historical posture never authorizes the new warm child. A valid boundary with no following posture therefore fails closed.

Summary

Functions

The marker kind stamped on every runtime-authored lineage boundary Event.

The runtime-authored boundary text.

The per-child envelope projection for warm-start lineage.

Create the warm-started child Log for child_session_id from seed_session_id.

Validate a seed reference without writing anything.

Functions

boundary_marker_kind()

@spec boundary_marker_kind() :: String.t()

The marker kind stamped on every runtime-authored lineage boundary Event.

boundary_text(seed_session_id)

@spec boundary_text(String.t()) :: String.t()

The runtime-authored boundary text.

Public so contract tests can pin the substance without reimplementing the wording.

envelope_projection(lineage)

@spec envelope_projection(map() | nil) :: map()

The per-child envelope projection for warm-start lineage.

Cold children report the absence of a seed rather than omitting the distinction, so an operator can tell a warm child from a cold one without reading Logs.

seed_child_log(child_session_id, seed_session_id, opts \\ [])

@spec seed_child_log(String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, map()}

Create the warm-started child Log for child_session_id from seed_session_id.

Fails before creating anything when the seed or requested posture is unusable, so no partial child Log is ever left behind. Returns the lineage evidence the envelope reports per child. The required :permission_posture option carries the requested child identity and effective permission/workspace fields; this module combines it with lineage from its own seed fold.

Pass :child_workspace when the child's Log lives somewhere other than the seed's workspace — an isolated Subagent runs in a snapshot directory, and snapshots exclude .pixir, so the seed Log is read from the delegate workspace and written into the child's. It defaults to the seed workspace (a shared-workspace child).

validate(seed_session_id, opts \\ [])

@spec validate(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, map()}

Validate a seed reference without writing anything.

Returns the resolved lineage (seed_session_id, fork_root_session_id, replay_event_count) so callers can reject a bad seed before any child Session is created. A seed that does not exist, is empty of replayable content, or lives outside the delegate workspace is rejected here.