From c23393b2cc9655eb42b649b32ee80b1138e2a0a2 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sat, 14 Nov 2026 14:26:39 +0000 Subject: [PATCH] Document conversation capture and continuation contracts --- docs/consumers/pkg-promptkit.md | 4 ++++ docs/roadmap/remediation.md | 6 +++++- exchange.go | 13 ++++++++++++- prepared_execution.go | 3 +++ types.go | 7 +++++++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/consumers/pkg-promptkit.md b/docs/consumers/pkg-promptkit.md index b3eb218..50cb346 100644 --- a/docs/consumers/pkg-promptkit.md +++ b/docs/consumers/pkg-promptkit.md @@ -697,6 +697,10 @@ its opaque rendered-prompt hash before invoking `RunPrepared`. ### Capture And Continue A Conversation +The [request GoDoc](../../types.go), [exchange GoDoc](../../exchange.go), and +[prepared-execution GoDoc](../../prepared_execution.go) own the exact capture, +continuation, inspection, and lifetime contracts. + Capture records the messages actually executed and the final assistant content. An exchange is an immutable in-process capability; `Details()` returns detached, encodable history that may contain sensitive content. Ordinary result encoding diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index 9c97d94..736181d 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -43,7 +43,11 @@ group members on each incremental update. ## 1. Complete The Public Exchange Capture And Continuation Contract -**Priority:** P2. **Status:** Open. **Plan stage:** 13. +**Priority:** P2. **Status:** Complete. **Plan stage:** 13. + +**Completion:** Expanded the public request, exchange, details, and prepared-handle +GoDoc and linked the consumer walkthrough to those owners. Checked comments +against capture, preparation, and repair behavior; local links and diff verified. **Locations:** [request fields](../../types.go), [exchange declarations and accessor](../../exchange.go), and diff --git a/exchange.go b/exchange.go index 09ac99d..721b8dc 100644 --- a/exchange.go +++ b/exchange.go @@ -7,17 +7,28 @@ const exchangeString = "promptkit.Exchange{opaque}" // Exchange is an immutable, reusable in-process snapshot of a completed // conversation. It is not a persistence or restart format. Different engines // can continue it, and independent branches do not alter one another. +// +// History preserves the effective request's message content, roles, and cache +// metadata, followed by the exact final [RunResult.RawOutput] as an assistant +// message. Intermediate structural-repair candidates and corrective instructions +// are excluded. A continuation extends that logical history according to +// [RunRequest.ContinueFrom], without changing its source exchange. type Exchange struct{ internal *domain.Exchange } // ExchangeDetails contains a detached copy of an exchange's logical history. type ExchangeDetails struct { - RunID string `json:"run_id"` + // RunID identifies the execution that produced this exchange. + RunID string `json:"run_id"` + // ParentRunID identifies the immediate source execution, or is empty. ParentRunID string `json:"parent_run_id,omitempty"` Messages []RenderedMessage `json:"messages"` } // Details returns detached history, or zero details for a nil or empty handle. // Messages include caller and model content and require appropriate handling. +// Inspection uses only retained state, without rendering, filesystem reads, or +// provider calls. Mutating returned messages or cache metadata cannot affect +// this exchange, another branch, or subsequent Details calls. func (e *Exchange) Details() ExchangeDetails { if e == nil || e.internal == nil { return ExchangeDetails{} diff --git a/prepared_execution.go b/prepared_execution.go index 5e38d4c..48e8e0f 100644 --- a/prepared_execution.go +++ b/prepared_execution.go @@ -15,6 +15,9 @@ const preparedExecutionString = "promptkit.PreparedExecution{opaque}" // A successful PrepareExecution may retain an Observer function in this // handle's private payload. The callback and other private execution settings // are cleared on claim completion or Discard. Details never exposes them. +// It also retains RunRequest.CaptureExchange and RunRequest.ContinueFrom for +// execution of the frozen snapshot. Only RunPrepared can produce its completed +// [Exchange]; preparation alone does not. type PreparedExecution struct { internal *usecase.PreparedExecution } diff --git a/types.go b/types.go index ef6d99d..56f131a 100644 --- a/types.go +++ b/types.go @@ -87,10 +87,17 @@ const ( type RunRequest struct { // CaptureExchange requests an immutable snapshot of a completed run, even // when its structural validation fails. Operational errors return no result. + // The snapshot is returned in RunResult.Exchange; see [Exchange] for its + // logical history contract. Prepare and ValidateRequest create no exchange. + // PrepareExecution retains this choice for its eventual RunPrepared call. CaptureExchange bool // ContinueFrom supplies captured history and implies capture of the new run. // A non-nil zero-value exchange is invalid. Follow-up settings are selected // normally and are not inherited from the exchange. + // Messages are assembled as captured history, rendered definition messages, + // then AppendedMessages. Prior templates and inputs are not rendered or read + // again. Continuation adds no history-size limit or truncation; upstream + // rejection follows the ordinary generation-error contract. ContinueFrom *Exchange `json:"-" yaml:"-"` // PromptID is the required prompt identifier. A namespace-scoped engine view // qualifies a slashless caller value; otherwise it selects the exact