Help us shape the future of Go! Take the 2026 Go Developer Survey

publicbody

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package publicbody projects a runtime's committed public event body onto the identities a client may hold (finding W1).

A harness public body names the RUNTIME session on every event (`session_id`, and again under `cause`) and, on an event a command caused, the RUNTIME command id (`cause.command_id`). Both are private: the runtime session id is the durable binding's, which Factory never shows a client, and the runtime command id is the once-allocated mapping Factory's store keeps beside the command a client admitted. Host relays these bodies to Factory, and Factory serves them to browsers on the live tail and from /journal, so a client that watched a session held both.

THE PROJECTION IS ONE FUNCTION APPLIED ON BOTH PATHS. Host applies it to the live tail, and a composition applies it to /journal through the reader host exports; a consumer joining its durable read to the live stream dedupes on (sequence, event id) and may compare bodies, so the two must produce the same bytes for the same event. They do because they are this code, fed the same identities: the public session id, the runtime session id, and the immutable public-to-runtime command mapping, which the live path reads from the session's disposition inbox and the journal path from the runtime journal's own application prefixes — two copies of one admission record.

WHAT IT CHANGES, and nothing else:

  • every occurrence of the runtime session id — any `session_id` value at any depth, and any mention inside a string (an error message, a path) — becomes the public session id;
  • the top-level `cause.command_id` becomes the public command id the client admitted, and so does every other occurrence of that runtime command id; or, when the runtime command has no public identity (a machine-originated cause: a subagent hand-back, a compaction waiter), it is REMOVED from `cause`, and a `cause` left empty by that removal is removed too, which is how the runtime encodes a zero cause.

Every other byte is carried: members keep their order, and a body naming neither identity is returned as the same bytes. Loop, turn and step ids are the runtime's own content identities with no private record behind them, and they stay.

PROJECTED BODIES ARE NOT HARNESS EVENTS ANY MORE, and no consumer should decode them with harness: a public command id need not be a UUID, and a Reply whose cause was a machine command loses the cause harness requires.

Index

Constants

This section is empty.

Variables

View Source
var ErrNonCanonical = errors.New("publicbody: the public body is not canonical JSON")

ErrNonCanonical reports a body this package would not hand on: one that is not canonical JSON on the way in, or whose projection would not be.

Functions

func Project

func Project(ctx context.Context, body json.RawMessage, ids Identities, seq uint64) (json.RawMessage, error)

Project returns body with its private identities replaced. seq is the event's journal sequence (see Commands).

IT IS LINEAR IN THE BODY, WHATEVER ITS NESTING (review S1). A body can carry model-controlled JSON — a tool call's input is embedded raw — so a projection that re-tokenised every subtree at every level cost depth × size (7.4 s for depth 1000 around a 1 MiB leaf). It now makes a fixed number of passes:

  • THE RUNTIME SESSION ID IS REPLACED AS BYTES, everywhere. A UUID is ASCII hex and hyphens, which JSON never escapes, so its encoding occurs only inside string tokens, literally; replacing it there rewrites every `session_id` value at any depth AND every free-text mention (review S2: a TurnFailed or RestoreErrored message, a capture-spill path) with one rule, and cannot produce invalid JSON because the replacement is the public id's own string encoding;
  • the TOP-LEVEL object alone is split into members, once, to find the header's `cause`. A mapped runtime command id is then replaced as bytes too, everywhere (it is as private as the session id); an unmapped one is a machine id, is removed from `cause` only, and an emptied `cause` goes with it.

func Projection

func Projection(ids Identities) func(context.Context, json.RawMessage, uint64) (json.RawMessage, error)

Projection binds Project to one session's identities, in the shape the live tail's projector takes.

Types

type Commands

type Commands interface {
	PublicCommand(ctx context.Context, runtime uuid.UUID, bound uint64) (sessionwire.CommandID, bool, error)
}

Commands resolves a runtime command id to the public command id a client admitted. ok is false when the runtime command has no public identity.

bound is the journal sequence of the event naming the command: a mapping that exists is durable at or below it, so a resolver that reads the journal need read no further.

type Identities

type Identities struct {
	// RuntimeSessionID is the runtime's own session id, the value to replace.
	RuntimeSessionID uuid.UUID

	// SessionID is the public (Core) session id, the value it becomes.
	SessionID sessionwire.SessionID

	// Commands maps runtime command ids. Nil maps none: every
	// cause.command_id is then removed.
	Commands Commands
}

Identities are what one session's bodies are projected with.

type Index

type Index struct {
	// contains filtered or unexported fields
}

Index is a Commands over a Source. It is safe for concurrent use; reads against one session are serialized.

func NewIndex

func NewIndex(source Source) *Index

NewIndex returns an empty index over source.

func (*Index) PublicCommand

func (i *Index) PublicCommand(ctx context.Context, runtime uuid.UUID, bound uint64) (sessionwire.CommandID, bool, error)

PublicCommand implements Commands.

type JournalSource

type JournalSource struct {
	Journal          RuntimeJournal
	TenantID         sessionwire.TenantID
	RuntimeSessionID sessionwire.SessionID
}

JournalSource reads a session's admission mappings from the runtime journal's own APPLICATION PREFIXES: harness writes one for every command it applies, carrying the public CommandID and the RuntimeCommandID it was admitted under, before any event that command causes. Positions are journal sequences, so it reads only as far as the event being projected.

It reads envelope FIELDS only. An application prefix has no body, and no runtime or public body is ever resolved here.

func (JournalSource) Read

func (s JournalSource) Read(ctx context.Context, after, bound uint64) ([]Pair, uint64, bool, error)

Read implements Source.

type MappingError

type MappingError struct{ Cause error }

MappingError reports a command mapping that could not be READ — a store or journal failure, not a finding about the body. It is the one projection failure a caller may retry: the same body projects once the read succeeds.

func (*MappingError) Error

func (e *MappingError) Error() string

func (*MappingError) Unwrap

func (e *MappingError) Unwrap() error

type Pair

type Pair struct {
	Runtime uuid.UUID
	Public  sessionwire.CommandID
}

Pair is one immutable admission mapping.

type RuntimeJournal

type RuntimeJournal interface {
	ReadRuntimeJournal(context.Context, sessionstore.ReadRuntimeJournalRequest) (sessionstore.RuntimePage, error)
}

RuntimeJournal is the privileged read of a runtime journal's every record. *sessionstore.Store satisfies it.

type Source

type Source interface {
	Read(ctx context.Context, after, bound uint64) (pairs []Pair, through uint64, done bool, err error)
}

Source reads a session's admission mappings incrementally.

Positions are the source's own (a journal sequence, an acceptance order) and only ever grow. Read returns the pairs recorded after `after`, the position it read through, and done when it has read enough to answer for an event at journal sequence bound — a source whose positions are not journal sequences reports done only at its end.

Jump to

Keyboard shortcuts

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