Goldie Blocks

Independent Block Agent Threads

Why each working-document block owns a separate reactive Goldie conversation

Decision

Block Goldie has one Convex Agent conversation per stable (documentKey, blockKey) pair. It is separate from the document/interview thread, but both agents read the same current persisted document state on every turn.

That shared state does not mean the full document is copied into a block turn. Block Goldie receives the selected block's complete authoritative facet source and metadata, its owning module identity, and the narrow document-wide reference catalogue needed to project and validate readable @ references. It does not receive other blocks' prose, other modules' agendas, or a writable vocabulary outside the selected block. A data-block turn additionally receives only that block's field declarations and current values.

The Inspector Panel is the general document location: Goldie operates over the full document on its document thread. The Control Panel is the scoped location: the current implementation binds one conversation to a block, and a module-scoped Control Panel is a decided follow-on whose thread and mutation contract has not landed yet. A block thread is never silently widened into a module or document thread.

blockAgentThreads is the root-schema binding table. Its business key uses the bat_ prefix and it stores documentKey, blockKey, and the Agent component's opaque threadId. A unique (documentKey, blockKey) index makes concurrent first prompts converge on one binding. It stores no messages.

The block agent is reactive only: it acts only on a submitted panel prompt. For a content block, Block Goldie may explain the block or propose an edit when the effective role is Builder or Maker. A Reader has no Block Goldie operation at all. A Builder may operate on the block whether its authored padlock is open or closed, and may set or clear that padlock. A Maker may operate on the block only while the padlock is open. The padlock is not specific to Goldie: while it is closed, it prevents a Maker from editing the block directly and prevents Block Goldie from explaining or proposing edits for that block in Maker mode. It therefore lets a Builder protect a block from Maker changes on the same document without preventing Builder edits.

Content and About turns return validated authored-string proposals; acceptance is explicit and compares the authoritative facet source before writing.

A Block Goldie request to change an existing Field value also returns a Proposed Change. It names only Fields in that Block's current vocabulary, shows each current and proposed value on the Field row, and waits for explicit acceptance. Acceptance compares each authoritative current value with the proposal's baseline, validates the proposed value against the current declaration, and applies the set atomically. A collection proposal carries the whole proposed list. Block Goldie never writes a Field value during the turn or claims an unaccepted value is current. Direct human Field entry and the document-level interview remain immediate writes.

On the Form surface, a Maker completes existing fields directly; a Builder may also propose that block's schema/DSL-backed form structure. A Reader has no Block Goldie operation. Structural form changes are proposals, never model writes, and require schema/DSL validation before display and acceptance. They open in About as a complete block declaration so the change has context, but a form_proposal may alter only the fields: body. Its handle, label, guide, display, and flow prefix must match the current block exactly. An about_proposal remains the separate authority for intentionally changing those system facets.

Consequences

Current: The separate thread binding, persisted Agent messages, authorized paginated transcript reader, resumed Control Panel history, block action, Content/About proposal flows, Builder form-structure proposals, and reviewed Block-agent scalar and collection Field-value proposals are implemented.

A collection is proposed whole: its proposed value is the complete array of items, so the agenda carries that Field's declared cardinality and item shape, and acceptance checks both — an array outside [min..max], an item that is not a set of named values, an item key the declaration does not have, or an item value of the wrong declared type is refused rather than stored. The before/after preview makes a shorter proposed list visible before acceptance; anything left out will be deleted only if the person accepts it.

Gap: See the archived plan 2026-08-06-independent-block-agent.

  • A handle rename or block-version change does not fork the conversation.
  • Switching blocks switches transcripts; the side-panel transcript never contains block-agent messages.
  • The Control Panel renders the bound block transcript as a conversation that grows to an approximately 320px ceiling and then scrolls internally. Closing, switching, and returning resume the same visible history. Reaching the top loads earlier pages without displacing the currently visible messages.
  • Transcript reads independently re-establish current document and block membership. Expected loss of access or stale context returns an empty page instead of throwing through the reactive UI.
  • Transcript history is conversational context, never authority. Fresh document state, capabilities, locks, and facet sources are injected each turn.
  • Pending proposals are UI state backed by the audited turn, not a proposals table. A newer proposal for the same block/facet supersedes the old one.

Revisit when

Cross-device proposal queues, multiple concurrent proposals, or shared block conversations are required. Each would need a separate persistence decision.

On this page