conversationprojection

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package conversationprojection implements the pure kernel for semantic message identity, never_backend exclusion filtering, deterministic projection/reassertion, anchor/provenance primitives, and immutable projection DTOs at the A-leg/B-leg boundary.

Projection is deterministic and content-preserving for unexcluded messages. This package contains zero stores, writers, locks, reflection, or network/storage I/O.

Index

Constants

View Source
const IdentityVersion1 = "v1"

IdentityVersion1 is the pinned prefix for version 1 message identities.

Variables

View Source
var (
	// ErrNonMessageItem is returned when an item is not a complete message item.
	ErrNonMessageItem = errors.New("conversationprojection: item is not a complete message item")

	// ErrEmptyMessage is returned when a message has no content parts.
	ErrEmptyMessage = errors.New("conversationprojection: message has no content parts")

	// ErrInvalidRole is returned when a message role is missing or invalid.
	ErrInvalidRole = errors.New("conversationprojection: invalid message role")

	// ErrInvalidMessageIdentity is returned when a message identity string is malformed or invalid.
	ErrInvalidMessageIdentity = errors.New("conversationprojection: invalid message identity")

	// ErrInvalidMessageAnchor is returned when a message anchor is invalid.
	ErrInvalidMessageAnchor = errors.New("conversationprojection: invalid message anchor")

	// ErrAnchorNotFound is returned when an anchor cannot be resolved in a trajectory.
	ErrAnchorNotFound = errors.New("conversationprojection: anchor not found")

	// ErrPartialContentNotSupported is returned when an identity or anchor operation targets a partial content part rather than a complete message.
	ErrPartialContentNotSupported = errors.New("conversationprojection: partial content part identity is not supported")

	// ErrAnchorMissing is returned when a required fixed anchor cannot be resolved.
	ErrAnchorMissing = errors.New("conversationprojection: anchor missing")

	// ErrProjectionFailed is returned when projection cannot produce a valid backend call.
	ErrProjectionFailed = errors.New("conversationprojection: projection failed")

	// ErrTerminalUserNotFound is returned when no terminal forwardable user message exists.
	ErrTerminalUserNotFound = errors.New("conversationprojection: terminal forwardable user message not found")

	// ErrTerminalNotUser is returned when the terminal forwardable message is not a user message.
	ErrTerminalNotUser = errors.New("conversationprojection: terminal forwardable message is not user")

	// ErrOverlayNotFound is returned when an overlay cannot be found for deactivation.
	ErrOverlayNotFound = errors.New("conversationprojection: overlay not found")

	// ErrALegNotFound is returned when conversation-view state is requested for an unknown A-leg.
	ErrALegNotFound = errors.New("conversationprojection: a-leg not found")

	// ErrInvalidPlacement is returned when a StoredPlacement fails validation.
	ErrInvalidPlacement = errors.New("conversationprojection: invalid placement")

	// ErrInvalidSteeringMessage is returned when a StoredMessageV1 fails validation.
	ErrInvalidSteeringMessage = errors.New("conversationprojection: invalid steering message")

	// ErrInvalidAnchorMissingPolicy is returned when an AnchorMissingPolicy value is invalid.
	ErrInvalidAnchorMissingPolicy = errors.New("conversationprojection: invalid anchor missing policy")

	// ErrInvalidReasonCode is returned when a ReasonCode is missing or exceeds bounds.
	ErrInvalidReasonCode = errors.New("conversationprojection: invalid reason code")

	// ErrInvalidOverlayID is returned when an overlay identifier is missing or exceeds bounds.
	ErrInvalidOverlayID = errors.New("conversationprojection: invalid overlay id")
)

Functions

func CanonicalAtomBytes

func CanonicalAtomBytes(atom MessageAtomV1) ([]byte, error)

CanonicalAtomBytes returns the deterministic JSON bytes for atom.

func CanonicalJSON

func CanonicalJSON(raw []byte) ([]byte, error)

CanonicalJSON recursively parses raw JSON and re-encodes it with sorted map keys and no insignificant whitespace.

func FilterNeverBackend

func FilterNeverBackend(call lipapi.Call, snap Snapshot) (lipapi.Call, error)

FilterNeverBackend returns a deep clone of call with all never_backend messages removed (including dangling item_reference cleanup) but without injecting steering. It is used to derive the filtered baseline for placement-aware reassertion.

func ResolveAnchor

func ResolveAnchor(items []lipapi.Item, anchor MessageAnchor) (int, bool, error)

ResolveAnchor locates the 0-based item index matching the anchor in items. If found, returns (index, true, nil). If not found, returns (-1, false, nil).

func VerifyAdaptationPreservesProjection

func VerifyAdaptationPreservesProjection(reasserted, adapted lipapi.Call, snap Snapshot, provenance []OverlayProvenance) error

VerifyAdaptationPreservesProjection checks that adaptedCall still satisfies full projection: - never_backend absent - steering exact count per identity, SlotOrdinal order, and same resolved placement (stable prefix / after anchor) - moved-tail/reordered steering rejects.

Types

type AnchorMissingPolicy

type AnchorMissingPolicy string

AnchorMissingPolicy controls behavior when a fixed anchor disappears.

const (
	AnchorStablePrefixFallback AnchorMissingPolicy = "stable_prefix_fallback"
	AnchorFailClosed           AnchorMissingPolicy = "fail_closed"
)

func (AnchorMissingPolicy) Validate

func (p AnchorMissingPolicy) Validate() error

type ContentKind

type ContentKind string

ContentKind classifies normalized content parts for semantic identity calculation.

const (
	ContentKindText         ContentKind = "text"
	ContentKindImageRef     ContentKind = "image_ref"
	ContentKindFileRef      ContentKind = "file_ref"
	ContentKindVideoRef     ContentKind = "video_ref"
	ContentKindRefusal      ContentKind = "refusal"
	ContentKindReasoning    ContentKind = "reasoning"
	ContentKindSummary      ContentKind = "summary"
	ContentKindAnnotation   ContentKind = "annotation"
	ContentKindAssistantRef ContentKind = "assistant_ref"
	ContentKindJSON         ContentKind = "json"
	ContentKindToolResult   ContentKind = "tool_result"
	ContentKindExtension    ContentKind = "extension"
)

type FallbackEvidence

type FallbackEvidence struct {
	OverlayID string        `json:"overlay_id"`
	Anchor    MessageAnchor `json:"anchor"`
}

FallbackEvidence records a deterministic stable-prefix fallback for a missing anchor.

type MessageAnchor

type MessageAnchor struct {
	Identity   MessageIdentity `json:"identity"`
	Occurrence uint32          `json:"occurrence"`
}

MessageAnchor pairs a replay-stable message identity with an explicit occurrence ordinal.

func ComputeCallAnchors

func ComputeCallAnchors(call lipapi.Call) ([]MessageAnchor, error)

ComputeCallAnchors computes occurrence-indexed MessageAnchors for all message units in call, supporting both item authority (Items) and legacy authority (Instructions + Messages).

func ComputeItemAnchors

func ComputeItemAnchors(items []lipapi.Item) ([]MessageAnchor, error)

ComputeItemAnchors computes occurrence-indexed MessageAnchors for all message items in items. Non-message items (e.g. tool calls, tool results) are skipped in the resulting anchor slice.

func ItemAnchorAt

func ItemAnchorAt(items []lipapi.Item, targetIndex int) (MessageAnchor, error)

ItemAnchorAt returns the MessageAnchor for the message item at targetIndex in items. If targetIndex is out of range, an error is returned. If the item at targetIndex is not ItemKindMessage, ErrNonMessageItem is returned.

func ResolveAfterIngressTailAnchor

func ResolveAfterIngressTailAnchor(call lipapi.Call, snap Snapshot) (MessageAnchor, error)

ResolveAfterIngressTailAnchor resolves the terminal forwardable user message in call (filtered by snap exclusions) to a MessageAnchor. It rejects if the terminal message is absent, not user, or not safe. It first establishes the concrete original terminal complete message boundary and rejects if that terminal's identity is in snapshot exclusions (never falls back to an earlier forwardable user).

func (MessageAnchor) String

func (a MessageAnchor) String() string

String returns the formatted anchor representation "v1:<hex>#<occurrence>".

func (MessageAnchor) Validate

func (a MessageAnchor) Validate() error

Validate checks that the anchor has a valid v1 identity and a non-zero occurrence ordinal.

type MessageAtomV1

type MessageAtomV1 struct {
	Role    lipapi.Role         `json:"role"`
	Content []NormalizedContent `json:"content"`
}

MessageAtomV1 is the internal representation-neutral projection of a complete message.

func AtomOfItem

func AtomOfItem(item lipapi.Item) (MessageAtomV1, error)

AtomOfItem projects a message item to its normalized MessageAtomV1.

func AtomOfMessage

func AtomOfMessage(msg lipapi.Message) (MessageAtomV1, error)

AtomOfMessage projects a legacy message to its normalized MessageAtomV1.

type MessageIdentity

type MessageIdentity string

MessageIdentity is the versioned replay-stable semantic digest of a complete message. Format: "v1:<64-char lowercase hex sha256>".

func HashAtom

func HashAtom(atom MessageAtomV1) (MessageIdentity, error)

HashAtom returns the versioned MessageIdentity for atom.

func ItemIdentityOf

func ItemIdentityOf(item lipapi.Item) (MessageIdentity, error)

ItemIdentityOf computes the versioned semantic identity for an item.

func MessageIdentityOf

func MessageIdentityOf(msg lipapi.Message) (MessageIdentity, error)

MessageIdentityOf computes the versioned semantic identity for a legacy message.

func ParseMessageIdentity

func ParseMessageIdentity(raw string) (MessageIdentity, error)

ParseMessageIdentity parses and validates a raw identity string.

func (MessageIdentity) Digest

func (id MessageIdentity) Digest() string

Digest returns the lowercase hex hash portion of this identity.

func (MessageIdentity) IsValid

func (id MessageIdentity) IsValid() bool

IsValid reports whether id is a valid v1 message identity.

func (MessageIdentity) String

func (id MessageIdentity) String() string

func (MessageIdentity) Validate

func (id MessageIdentity) Validate() error

Validate checks that id conforms to "v1:<64-char lowercase hex sha256>".

func (MessageIdentity) Version

func (id MessageIdentity) Version() string

Version returns the version prefix of this identity (e.g. "v1").

type NormalizedAnnotation

type NormalizedAnnotation struct {
	Type string          `json:"type,omitempty"`
	Data json.RawMessage `json:"data,omitempty"`
}

NormalizedAnnotation holds deterministic annotation data.

type NormalizedContent

type NormalizedContent struct {
	Kind ContentKind `json:"kind"`

	Text string `json:"text,omitempty"`

	ImageRef  string `json:"image_ref,omitempty"`
	ImageMIME string `json:"image_mime,omitempty"`

	FileRef  string `json:"file_ref,omitempty"`
	FileData string `json:"file_data,omitempty"`
	FileMIME string `json:"file_mime,omitempty"`
	FileName string `json:"file_name,omitempty"`

	VideoRef  string `json:"video_ref,omitempty"`
	VideoMIME string `json:"video_mime,omitempty"`

	Refusal string `json:"refusal,omitempty"`

	Reasoning *NormalizedReasoning `json:"reasoning,omitempty"`

	Summary string `json:"summary,omitempty"`

	Annotation *NormalizedAnnotation `json:"annotation,omitempty"`

	AssistantRef string `json:"assistant_ref,omitempty"`

	JSON json.RawMessage `json:"json,omitempty"`

	Extension *NormalizedExtension `json:"extension,omitempty"`
}

NormalizedContent is one ordered semantic content fragment in a message atom.

type NormalizedExtension

type NormalizedExtension struct {
	Namespace   string          `json:"namespace,omitempty"`
	Type        string          `json:"type"`
	Implementor string          `json:"implementor,omitempty"`
	Data        json.RawMessage `json:"data,omitempty"`
}

NormalizedExtension carries vendor-prefixed custom content parts.

type NormalizedReasoning

type NormalizedReasoning struct {
	Dialect                 string          `json:"dialect,omitempty"`
	Text                    string          `json:"text,omitempty"`
	Signature               string          `json:"signature,omitempty"`
	Opaque                  json.RawMessage `json:"opaque,omitempty"`
	Summary                 json.RawMessage `json:"summary,omitempty"`
	Content                 json.RawMessage `json:"content,omitempty"`
	EncryptedContent        json.RawMessage `json:"encrypted_content,omitempty"`
	EncryptedContentPresent bool            `json:"encrypted_content_present,omitempty"`
}

NormalizedReasoning holds normalized reasoning metadata and payload.

type Observer

type Observer interface {
	OnProjection(stage Stage, summary ProjectionSummary)
	OnProjectionFailure(stage Stage)
	OnAnchorFallback(stage Stage, policy AnchorMissingPolicy)
	OnAnchorFailure(policy AnchorMissingPolicy)
}

Observer receives bounded, content-free diagnostics for conversation-view events.

type Overlay

type Overlay struct {
	OverlayID           string              `json:"overlay_id"`
	Revision            uint64              `json:"revision"`
	SlotOrdinal         uint64              `json:"slot_ordinal"`
	Active              bool                `json:"active"`
	Message             OverlayMessage      `json:"message"`
	Placement           Placement           `json:"placement"`
	AnchorMissingPolicy AnchorMissingPolicy `json:"anchor_missing_policy"`
}

Overlay is the pure immutable per-turn steering record.

func (Overlay) Clone

func (o Overlay) Clone() Overlay

type OverlayID

type OverlayID = string

OverlayID alias for documentation.

type OverlayMessage

type OverlayMessage struct {
	Role lipapi.Role `json:"role"`
	Text string      `json:"text"`
}

OverlayMessage is the model-visible steering payload.

type OverlayProvenance

type OverlayProvenance struct {
	OverlayID        string          `json:"overlay_id"`
	Revision         uint64          `json:"revision"`
	SlotOrdinal      uint64          `json:"slot_ordinal"`
	ResolvedKind     PlacementKind   `json:"resolved_kind"`
	ResolvedAnchor   *MessageAnchor  `json:"resolved_anchor,omitempty"`
	InjectedIdentity MessageIdentity `json:"injected_identity"`
	// Exact injected position for placement-aware reassertion.
	InjectedAuthority           string `json:"injected_authority"`            // "item" or "legacy"
	InjectedItemIndex           int    `json:"injected_item_index,omitempty"` // valid when authority == "item"
	InjectedLegacyIsInstruction *bool  `json:"injected_legacy_is_instruction,omitempty"`
	InjectedLegacyIndex         *int   `json:"injected_legacy_index,omitempty"`
	InjectedTrajectoryIndex     int    `json:"injected_trajectory_index"`
}

OverlayProvenance is deterministic request-local provenance for one injected overlay. It is derived solely from Snapshot + input call and is used by a later final-reassertion stage to recognize/rebuild/remove projection-owned steering instances without string heuristics. It does not affect MessageIdentityOf values or model-visible content. Injected* fields record the exact trajectory position of the injected copy for placement-aware reassertion without broad identity sweeps.

func (OverlayProvenance) MatchesItem

func (p OverlayProvenance) MatchesItem(item lipapi.Item) bool

MatchesItem reports whether item is the projection-owned copy for this provenance entry.

func (OverlayProvenance) MatchesMessage

func (p OverlayProvenance) MatchesMessage(msg lipapi.Message) bool

MatchesMessage reports whether msg is the projection-owned copy for this provenance entry by semantic identity comparison. It is pure and uses no string-marker heuristics.

type Placement

type Placement struct {
	Kind   PlacementKind  `json:"kind"`
	Anchor *MessageAnchor `json:"anchor,omitempty"`
}

Placement describes where an overlay should be injected.

func (Placement) Validate

func (p Placement) Validate() error

type PlacementKind

type PlacementKind string

PlacementKind enumerates durable steering placement.

const (
	PlacementStablePrefix PlacementKind = "stable_prefix"
	PlacementAfterMessage PlacementKind = "after_message"
)

func (PlacementKind) Validate

func (k PlacementKind) Validate() error

type ProjectionEvidence

type ProjectionEvidence struct {
	FilteredCount int                 `json:"filtered_count"`
	InjectedCount int                 `json:"injected_count"`
	Fallbacks     []FallbackEvidence  `json:"fallbacks,omitempty"`
	Provenance    []OverlayProvenance `json:"provenance,omitempty"`
}

ProjectionEvidence captures bounded diagnostics for a successful projection.

func Project

func Project(call lipapi.Call, snap Snapshot) (lipapi.Call, *ProjectionEvidence, error)

Project derives the backend-effective call from call and snap. It is pure, deterministic and never mutates the input call. Exclusion is applied first, then steering injection; result is validated.

func Reassert

func Reassert(call lipapi.Call, snap Snapshot, provenance []OverlayProvenance, filteredBaseline lipapi.Call) (lipapi.Call, *ProjectionEvidence, error)

Reassert restores the frozen conversation view after late attempt/candidate/interleaved transforms. It is pure and uses no store read. It removes any reintroduced never_backend messages and ensures each active overlay in snap is present exactly once at its frozen placement (rebuild via Project). It handles late calls that are already based on the projected baseline by stripping existing projection-owned copies (identified via placement-aware provenance) before re-projecting, to avoid duplicate injection. Identity collisions are handled by using exact injected trajectory positions (InjectedTrajectoryIndex / InjectedItemIndex / InjectedLegacy*) plus anchor/slot order, preserving legitimate same role/text messages. If ambiguity remains (multiple identical copies indistinguishable), it fails closed rather than silently deleting. FilteredBaseline is the frozen filtered call (without never_backend, without steering) carried from early projection; when provided it is used to distinguish legitimate user collisions from duplicate steering. If empty, it is derived on the fly.

type ProjectionSummary

type ProjectionSummary struct {
	StateRevision      uint64 `json:"state_revision"`
	FilteredCount      int    `json:"filtered_count"`
	InjectedCount      int    `json:"injected_count"`
	StablePrefixCount  int    `json:"stable_prefix_count"`
	AfterMessageCount  int    `json:"after_message_count"`
	FallbackCount      int    `json:"fallback_count"`
	MaxOverlayRevision uint64 `json:"max_overlay_revision"`
	MaxSlotOrdinal     uint64 `json:"max_slot_ordinal"`
}

ProjectionSummary is a bounded, content-free diagnostic summary of a projection operation. It contains only counts, revisions, and placement classes (no plaintext, IDs, or digests).

func NewProjectionSummary

func NewProjectionSummary(snap Snapshot, ev *ProjectionEvidence) ProjectionSummary

NewProjectionSummary builds a content-free ProjectionSummary from a snapshot and evidence.

type Reader

type Reader interface {
	Snapshot(ctx context.Context, aLegID string) (Snapshot, error)
}

Reader is the narrow read-only port for obtaining an A-leg snapshot.

type ReasonCode

type ReasonCode string

ReasonCode is a non-secret identifier for diagnostics.

func (ReasonCode) Validate

func (r ReasonCode) Validate() error

type Snapshot

type Snapshot struct {
	StateRevision uint64    `json:"state_revision"`
	NeverBackend  []Tag     `json:"never_backend"`
	Steering      []Overlay `json:"steering"`
}

Snapshot is the coherent per-turn conversation view.

type Stage

type Stage = string

Stage identifies the projection stage in diagnostics.

const (
	StageEarly      Stage = "early"
	StageFinal      Stage = "final"
	StageLate       Stage = "late"
	StageSDKResolve Stage = "sdk_resolve"
)

type Tag

type Tag struct {
	Identity  MessageIdentity `json:"identity"`
	Reason    ReasonCode      `json:"reason,omitempty"`
	CreatedAt time.Time       `json:"created_at"`
}

Tag is an A-leg never_backend exclusion record.

func (Tag) Validate

func (t Tag) Validate() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL