Data

Conversation records are folded into signed tables before you can query their messages, tool calls, approvals, and payments. Data exposes those tables read-only, restricted to what your credential admits.

The signed, append-only log records conversation events. The projector folds those events into tables you can query with SQL — a query reads the tables, never the log, and cannot write to either.

From signed events to SQLFollow a message from the log to a row.Three fictional conversations. One query. Change the scope to see what reaches the result.
Query as
The signed log records every turn
conv-aIn scope
Your completed conversation
  1. Turn starts
  2. Message
  3. Turn completes
conv-bIn scope
Your unfinished conversation
  1. Turn starts
  2. Message
  3. No completion
conv-cOutside your scope
Another person's conversation
  1. Turn starts
  2. Message
  3. Turn completes
The projector folds committed turns into signed tables
Fold events into facts

Shared folds turn log records into typed rows ahead of any query. The projection adds the partition, source incarnation, position, and turn id.

Signed log eventpartition · source_incarnation · position · turn_id

The log stays unchanged, and an unfinished turn folds to nothing — conv-b yields no rows for anyone.

Your grant's realm names 2 in-scope partitions' tables
Query the rows you can read
Try a table
SQL
SELECT partition, position, role, text
FROM messages
ORDER BY partition, position;
1 row returned from messages.
Illustrative query result
partitionposition
conv-a1

conv-b is in scope, but its turn is unfinished, so it folded to no rows. conv-c is outside your scope. Only the row from conv-a reaches this result.

Read-only throughout. This illustration uses sample rows, not a live query.

Shared event interpretation

Decoding reads an event's payload. A fold interprets events to derive a fact, such as a settled payment. Separate implementations can disagree about which events count.

A decoded payment receipt does not establish that its signature is valid. If a dashboard skips verification, it can display a forged receipt as settled. A spending check that verifies signatures would reject the same receipt.

polyc-facts provides shared folds for readers. Spending checks call a fold directly, and the projector uses the same fold to build the tables a query reads. Both therefore apply the same payment rules.

The tables

The projection adds identifying columns no log event carries:

  • partition — the conversation the row belongs to, written conv-{id}.
  • source_incarnation — which incarnation of the source partition produced the row.
  • position — the row's position in append-only order.
  • turn_id — the turn the row belongs to. The log records it three different ways. The fold normalizes them into one column.

These columns identify rows folded from individual log events. Deployment-wide tables — persona records, credential history, query audit — carry their own keys instead. Start with turns, which every participant grant can name:

SQL
-- Inspect committed turns
SELECT * FROM turns LIMIT 5;

-- Count input and output tokens per turn
SELECT turn_id,
       SUM(input_tokens)  AS input_tokens,
       SUM(output_tokens) AS output_tokens
FROM usage
GROUP BY turn_id
ORDER BY turn_id;

-- Find tool calls without a recorded result
SELECT c.name, c.turn_id, c.position
FROM tool_calls c
LEFT JOIN (SELECT tool_call_id FROM tool_calls WHERE block_type = 'result') r
       ON r.tool_call_id = c.tool_call_id
WHERE c.block_type = 'call'
  AND r.tool_call_id IS NULL
ORDER BY c.position DESC;

A tool call, result, approval, and receipt share a call id. tool_calls and payments name it tool_call_id. approvals names it request_id. Join these columns to inspect the transaction.

SQL
-- List settled payments with their approvals
SELECT p.reference, p.amount_base_units, p.asset, a.tool_name, a.outcome
FROM payments p
JOIN approvals a ON a.request_id = p.tool_call_id
ORDER BY p.position DESC;

The catalog lists the tables your credential's realm may name. A participant grant names the conversation tables; a fleet grant names all of them. Your scope then bounds which partitions' rows appear. Names outside the realm fail to resolve before execution.

Browse by access
74 of 74 tables

Any scope 37

Available in every session. Rows still follow your conversation scope.

turns 4 key columnsOne committed turn in one conversation partition.
Key columns
  • turn_id
  • first_position
  • start_position
  • complete_position
messages 6 key columnsOne text block of a committed turn.
Key columns
  • turn_id
  • role
  • internal_only
  • incomplete
  • text
  • trust

A row a turn marks internal_only lands only in the fleet segment, so outside admin this column always reads false.

usage 3 key columnsOne turn's token count.
Key columns
  • turn_id
  • input_tokens
  • output_tokens
model_call 4 key columnsOne call to the model inside a turn.
Key columns
  • turn_id
  • provider
  • model
  • captured_clock_unix_ms
tool_calls 9 key columnsOne tool invocation and its result, as the model saw them.
Key columns
  • turn_id
  • tool_call_id
  • block_type
  • name
  • arguments
  • result
  • first_party
  • internal_only
  • trust

Like messages, internal_only rows land only in the fleet segment and read false outside admin.

turn_failed 3 key columnsOne turn that ends in a failure, and the kind of failure.
Key columns
  • turn_id
  • failure_kind
  • message
turn_dispatch 6 key columnsOne turn the control plane recorded, with who may see it.
Key columns
  • turn_id
  • occurrence
  • visibility
  • visibility_source
  • source_turn_id
  • edge_asserted_visibility
approvals 10 key columnsOne approval gate a tool call paused on, and its verdict.
Key columns
  • turn_id
  • request_id
  • tool_name
  • args_json
  • outcome
  • response_reason
  • signature_status
  • routine_grant
  • tool_descriptor_hash
  • grant_scope

Who approved, the caller, and any edited arguments live in the fleet-only approval_details table.

attribution 3 key columnsThe persona that a turn runs as, and each persona that takes part.
Key columns
  • turn_id
  • persona_id
  • role

The identity assertion's provenance — provider, external id, signing edge — is fleet-only in attribution_provenance.

routine_grant_mutations 7 key columnsOne standing-allowance grant a routine set up, changed, or dropped.
Key columns
  • turn_id
  • tool_name
  • tool_descriptor_hash
  • grant_scope
  • approved
  • response_reason
  • signature_status
grant_replays 6 key columnsOne capability grant that authorizes one tool call.
Key columns
  • turn_id
  • tool
  • grant_ref
  • covered_capabilities
  • coverage_hash
  • signature_status

The signing key lives in the fleet-only grant_replay_signers table.

handoffs 10 key columnsOne transfer to another agent, or one refusal to transfer.
Key columns
  • turn_id
  • phase
  • child_conversation_id
  • child_agent_id
  • carried_count
  • reason
  • parent_agent_id
  • denial_reason
  • allowed
  • signature_status

A column the row's phase does not carry reads null: `carried_count` and `child_conversation_id` on a refusal, `allowed`, `parent_agent_id` and `denial_reason` on a transfer. The signing key lives in the fleet-only handoff_signers table.

payments 11 key columnsOne verified inbound payment receipt: what this deployment charged a subject.
Key columns
  • subject
  • amount_base_units
  • asset
  • reference
  • recipient
  • method
  • tool_call_id
  • turn_id
  • direction
  • payer_kind
  • timestamp_unix
outbound_payments 11 key columnsOne verified outbound receipt: what settled out of a subject's own delegated wallet.
Key columns
  • subject
  • amount_base_units
  • asset
  • reference
  • recipient
  • method
  • tool_call_id
  • turn_id
  • direction
  • payer_kind
  • timestamp_unix
refusals 9 key columnsOne outbound payment attempt the deployment blocked before it settled.
Key columns
  • subject
  • reason
  • merchant_host
  • requested_base_units
  • permitted_base_units
  • tool_call_id
  • timestamp_unix
  • turn_id
  • reason_detail
wallet_link_lifecycle 8 key columnsOne wallet link, renewal, or revocation step.
Key columns
  • subject
  • transition
  • asset
  • chain_id
  • limit_base_units
  • period_secs
  • expiry_unix
  • timestamp_unix
trace_turns 29 key columnsOne turn as a trace row: status, model, usage, and caller persona.
Key columns
  • turn_id
  • first_position
  • status
  • has_start
  • has_dispatched
  • has_complete
  • has_failed
  • has_ambiguous
  • failed_kind
  • failed_message
  • failed_position
  • has_failed_position
  • model_provider
  • model_name
  • system_config_ref
  • temperature_micros
  • has_temperature
  • top_p_micros
  • has_top_p
  • max_tokens
  • has_max_tokens
  • reasoning_level
  • dispatch_clock_ms
  • has_dispatch_clock
  • usage_input
  • usage_output
  • has_usage
  • caller_persona_id
  • plannable
trace_steps 7 key columnsOne step in a turn's trace.
Key columns
  • ordinal
  • turn_id
  • step_kind
  • kind_base
  • trust
  • truncated
  • internal_only
trace_boundaries 8 key columnsOne visibility boundary marker inside a trace.
Key columns
  • ordinal
  • marker
  • audience
  • audience_source
  • edge_asserted
  • source_turn_id
  • failed_kind
  • failed_message
trace_messages 6 key columnsOne message inside a turn's trace.
Key columns
  • ordinal
  • turn_id
  • role
  • text
  • truncated
  • internal_only
trace_tool_calls 10 key columnsOne tool call inside a trace, with its result linkage.
Key columns
  • ordinal
  • turn_id
  • tool_call_id
  • name
  • arguments
  • truncated
  • status
  • origin_turn_id
  • result_turn_id
  • internal_only
trace_tool_results 9 key columnsOne tool result inside a trace.
Key columns
  • ordinal
  • turn_id
  • tool_call_id
  • name
  • result
  • first_party
  • truncated
  • needs_wallet_link
  • internal_only
trace_approvals 11 key columnsOne approval request or decision inside a trace.
Key columns
  • ordinal
  • turn_id
  • phase
  • request_id
  • tool_name
  • args
  • decision
  • reason
  • signature
  • sig_valid
  • has_sig_valid
trace_questions 14 key columnsOne structured question the agent asked inside a trace.
Key columns
  • ordinal
  • turn_id
  • phase
  • call_id
  • index
  • header
  • question
  • args
  • decision
  • selected_index
  • has_selected_index
  • selected_label
  • answered_by
  • verdict
trace_subagents 17 key columnsOne subagent delegation inside a trace.
Key columns
  • ordinal
  • turn_id
  • phase
  • sub_agent_id
  • target_agent_id
  • task
  • provider
  • model
  • succeeded
  • has_succeeded
  • error
  • input_tokens
  • output_tokens
  • has_tokens
  • first_party
  • has_first_party
  • verdict
trace_handoffs 10 key columnsOne handoff inside a trace.
Key columns
  • ordinal
  • turn_id
  • phase
  • child_conversation_id
  • child_agent_id
  • carried_count
  • reason
  • parent_agent_id
  • denial_reason
  • verdict
trace_payment_attempts 10 key columnsOne payment attempt inside a trace.
Key columns
  • ordinal
  • turn_id
  • approval_pos
  • has_approval_pos
  • tool_call_id
  • approved_args_hash
  • url
  • currency
  • challenge_amount
  • challenge_id
trace_payment_receipts 15 key columnsOne payment receipt inside a trace.
Key columns
  • ordinal
  • turn_id
  • direction
  • reference
  • amount
  • currency
  • recipient
  • method
  • tool_call_id
  • approval_pos
  • has_approval_pos
  • approved_args_hash
  • subject
  • kind
  • payer_kind
trace_payment_refusals 10 key columnsOne payment refusal inside a trace.
Key columns
  • ordinal
  • turn_id
  • reason
  • reason_detail
  • merchant_host
  • requested_base_units
  • permitted_base_units
  • tool_call_id
  • subject
  • timestamp
trace_wallet_links 11 key columnsOne wallet-link transition inside a trace.
Key columns
  • ordinal
  • transition
  • subject
  • currency
  • chain_id
  • limit_base_units
  • limit_human
  • period_secs
  • expiry_unix
  • conversation_id
  • timestamp
trace_records 22 key columnsOne miscellaneous record inside a trace: grants, identity, summary, or marker.
Key columns
  • ordinal
  • turn_id
  • record_kind
  • tool
  • grant_ref
  • coverage_hash
  • verdict
  • identity_provider
  • identity_scope
  • external_id
  • display_name
  • persona_id
  • text
  • truncated
  • covers_through_position
  • gate_rejected
  • gate_count
  • marker
  • marker_on
  • has_marker_on
  • escalated_at_ms
  • has_escalated_at
trace_failures 4 key columnsOne failure record ranked inside a trace.
Key columns
  • turn_id
  • rank
  • kind
  • message
trace_warnings 4 key columnsOne warning emitted inside a trace.
Key columns
  • ordinal
  • code
  • message
  • has_position
trace_lists 7 key columnsOne list item inside a trace.
Key columns
  • owner_kind
  • ordinal
  • turn_id
  • list_kind
  • index
  • text_value
  • numeric_value
memory_portable_facts 8 key columnsOne portable fact: memory a persona allows across conversations.
Key columns
  • fact_id
  • text
  • event_time_ms
  • ingested_at_ms
  • valid_from_ms
  • confidence_bps
  • scope
  • durability
memory_portable_invalidations 5 key columnsOne invalidation of a portable fact.
Key columns
  • fact_id
  • invalid_at_ms
  • reason
  • superseded_by_fact_id
  • fact_scope
memory_portable_lists 5 key columnsOne item in a portable list.
Key columns
  • owner_kind
  • owner_id
  • list_kind
  • index
  • text_value

Narrowed by scope 7

Your scope determines which partitions' rows appear.

memory_facts 8 key columnsOne private fact a persona's memory extracted.
Key columns
  • fact_id
  • text
  • event_time_ms
  • ingested_at_ms
  • valid_from_ms
  • confidence_bps
  • scope
  • durability

Only the partition the owning persona owns carries rows for your scope.

memory_invalidations 5 key columnsOne invalidation of a private fact.
Key columns
  • fact_id
  • invalid_at_ms
  • reason
  • superseded_by_fact_id
  • fact_scope
memory_lists 5 key columnsOne item in a private list.
Key columns
  • owner_kind
  • owner_id
  • list_kind
  • index
  • text_value
memory_corroborations 5 key columnsOne corroboration linking a private fact to its origin turn.
Key columns
  • fact_id
  • origin_conversation_id
  • origin_turn_exec_id
  • origin_turn_id
  • at_ms
memory_extractions 5 key columnsOne extraction pass over a turn: how many facts it added or invalidated.
Key columns
  • conversation_id
  • turn_exec_id
  • extracted_at_ms
  • facts_added
  • facts_invalidated
memory_profile_rewrites 2 key columnsOne rewrite of a persona's profile document.
Key columns
  • document
  • updated_at_ms
memory_summaries 4 key columnsOne private summary of a conversation.
Key columns
  • conversation_id
  • summary_text
  • event_time_ms
  • scope

Admin only 30

These table names are registered only in admin sessions.

summary 3 key columnsOne compaction of the older part of the transcript.
Key columns
  • summary_id
  • text
  • covers_through_position
approval_details 9 key columnsThe signing-side detail of one approval: caller, approver, edited arguments.
Key columns
  • request_reason
  • request_sandbox_mode
  • signer_public_key
  • modified_args_json
  • approved_for_session
  • caller
  • approver
  • response_sandbox_mode
  • injected_context

The whole table. A participant session reads the verdict in `approvals`.

attribution_provenance 7 key columnsWho asserted one identity: provider, external id, and the signing edge.
Key columns
  • identity_provider
  • identity_scope
  • identity_external_id
  • identity_display_name
  • asserting_edge_id
  • signer_pk_hex
  • signature_hex
grant_replay_signers 2 key columnsThe key that signed one replayed capability grant.
Key columns
  • signer_pk_hex
  • signature_hex
handoff_signers 2 key columnsThe key that signed one transfer record.
Key columns
  • signed_by
  • signer_key_id

The whole table. `handoffs` carries the verdict, never the key, so a participant session reads `signature_status` and cannot reach this table at all.

trace_signers 4 key columnsThe key that signed one step inside a trace.
Key columns
  • ordinal
  • step_kind
  • role
  • signer_key
trace_participant_addresses 3 key columnsThe onchain address on one payment receipt or wallet-link step inside a trace.
Key columns
  • ordinal
  • step_kind
  • address

The whole table. A participant's own address exposes its whole balance and history, so `trace_payment_receipts` and `trace_wallet_links` do not carry it.

admin_model_changes 7 key columnsOne signed change of a conversation's model or provider by an administrator.
Key columns
  • signature_status
  • principal
  • previous_provider
  • previous_model
  • new_provider
  • new_model
  • changed_at_ms
query_audit_intents 8 key columnsOne query the Query plane recorded before it ran.
Key columns
  • namespace
  • query_id
  • requester
  • shape_digest
  • recorded_at_nanos
  • source_pin_count
  • command_id
  • command_digest
query_audit_completions 11 key columnsThe outcome of one audited query.
Key columns
  • namespace
  • query_id
  • intent_position
  • outcome
  • error_class
  • duration_nanos
  • rows
  • truncation
  • truncated_at
  • command_id
  • command_digest
query_audit_source_pins 16 key columnsThe exact projection generation and evidence one audited query read.
Key columns
  • namespace
  • query_id
  • pin_index
  • pin_kind
  • family
  • source_partition
  • pin_source_incarnation
  • projection_generation
  • evidence_kind
  • evidence_position
  • evidence_journal_position
  • schema_version
  • fact_version
  • artifact_digest
  • anchor_head
  • revision
credential_lifecycle 14 key columnsOne revision of a query credential: capabilities, namespaces, revocation.
Key columns
  • namespace
  • revision
  • change_kind
  • entry_digest
  • credential_id
  • principal
  • cap_edge
  • cap_administrator
  • cap_attest_email
  • cap_may_assert_direct
  • cap_forensics_read
  • allowed_namespaces
  • revoked
  • revoked_at_ms
credential_key_lifecycle 9 key columnsOne key's activation, expiry, and confirmation inside a credential.
Key columns
  • namespace
  • credential_id
  • key_id
  • state
  • activated_at_ms
  • has_not_after
  • not_after_ms
  • has_confirmed_at
  • confirmed_at_ms
credential_lifecycle_refusals 3 key columnsOne refused credential change, and the refusal reason.
Key columns
  • namespace
  • change_kind
  • reason
routine_lifecycle 12 key columnsOne lifecycle event of a routine: published, paused, resumed, removed.
Key columns
  • phase
  • routine
  • actor_persona
  • conversation_id
  • at_ms
  • has_reason
  • reason
  • has_scope
  • scope
  • has_channel
  • channel
  • signer_public_key
routine_setup 1 key columnsThe routine uid one setup pass registered.
Key columns
  • routine_uid
fires 9 key columnsOne firing of a routine: scheduled time, actual time, outcome.
Key columns
  • routine
  • routine_uid
  • occurrence
  • scheduled_at_ms
  • fired_at_ms
  • has_outcome
  • outcome
  • has_grant_drift
  • grant_drift_tools

The whole table is fleet-only; a participant session cannot name it.

observed_routines 40 key columnsOne observed state of a routine, as the watcher recorded it.
Key columns
  • namespace
  • observation_ordinal
  • observation_resource_version
  • observed_at_ms
  • recorded_at_ms
  • observer
  • name
  • uid
  • resource_version
  • generation
  • fire_conversation_id
  • creator_persona
  • provenance_conversation_id
  • scope
  • display_name
  • description
  • schedule_json
  • schedule_timezone
  • next_fires_json
  • prompt
  • prompt_truncated
  • ready
  • has_phase
  • phase
  • has_message
  • message
  • has_last_fire_time_ms
  • last_fire_time_ms
  • has_next_fire_time_ms
  • next_fire_time_ms
  • conditions_json
  • suspended
  • has_paused_by
  • paused_by
  • has_paused_at_ms
  • paused_at_ms
  • has_pause_reason
  • pause_reason
  • orphaned
  • setup_completed
persona_profiles 25 key columnsOne revision of a persona's profile record.
Key columns
  • namespace
  • entry_digest
  • persona_id
  • display_name
  • status
  • created_at_ms
  • merged_into
  • merged_by
  • merge_evidence
  • merged_at_ms
  • removed_by
  • removed_at_ms
  • split_from
  • split_by
  • split_reason
  • split_at_ms
  • profile_language
  • profile_tone
  • profile_updated_at_ms
  • profile_preferences
  • tool_grants
  • approval_policy
  • turn_quota
  • auto_review
  • identities
persona_identities 15 key columnsOne linked identity of a persona, with its link evidence.
Key columns
  • namespace
  • entry_digest
  • deleted
  • persona_id
  • surface
  • scope
  • subject
  • display_name
  • time_zone
  • first_seen_ms
  • last_seen_ms
  • link_method
  • linked_by
  • link_evidence
  • verified_at_ms
persona_participations 9 key columnsOne persona's participation in one scope.
Key columns
  • namespace
  • entry_digest
  • deleted
  • persona_id
  • scope
  • role
  • first_at_ms
  • has_via_persona
  • via_persona
persona_visibility 10 key columnsOne visibility setting a persona holds in a scope.
Key columns
  • namespace
  • entry_digest
  • deleted
  • persona_id
  • scope
  • hidden
  • set_at_ms
  • set_by
  • has_via_persona
  • via_persona
persona_refusals 3 key columnsOne refused persona-directory change.
Key columns
  • namespace
  • record_kind
  • reason
persona_profiles_current 25 key columnsThe current profile of a persona, after merge and removal folds.
Key columns
  • namespace
  • entry_digest
  • persona_id
  • display_name
  • status
  • created_at_ms
  • merged_into
  • merged_by
  • merge_evidence
  • merged_at_ms
  • removed_by
  • removed_at_ms
  • split_from
  • split_by
  • split_reason
  • split_at_ms
  • profile_language
  • profile_tone
  • profile_updated_at_ms
  • profile_preferences
  • tool_grants
  • approval_policy
  • turn_quota
  • auto_review
  • identities
persona_identities_current 15 key columnsThe current identity set of a persona.
Key columns
  • namespace
  • entry_digest
  • deleted
  • persona_id
  • surface
  • scope
  • subject
  • display_name
  • time_zone
  • first_seen_ms
  • last_seen_ms
  • link_method
  • linked_by
  • link_evidence
  • verified_at_ms
persona_participations_current 9 key columnsThe current participation set of a persona.
Key columns
  • namespace
  • entry_digest
  • deleted
  • persona_id
  • scope
  • role
  • first_at_ms
  • has_via_persona
  • via_persona
memory_provenance_identity 6 key columnsThe identity assertion attached to one memory record.
Key columns
  • record_kind
  • record_id
  • identity_provider
  • identity_scope
  • identity_external_id
  • identity_display_name
memory_fences 0 key columnsOne extraction fence marker: where memory work stands in a partition.
memory_unknown 1 key columnsOne record the memory fold could not classify.
Key columns
  • kind
settlements 5 key columnsOne outbound payment attempt and whether a verified receipt settled it.
Key columns
  • subject
  • outcome
  • amount_base_units
  • asset
  • tool_call_id

Only committed turns

The control plane records dispatch intent through the state plane before calling the harness. It records the commit marker after the harness returns. A crash between these writes can leave records for an unfinished turn, including one that caused an external effect.

A turn-derived table gains a row only when its conversation and turn have turn_start and turn_complete markers. An unfinished turn's events are folded into nothing, so no realm can read them — there is no raw-events escape hatch. Tables that are not turn-scoped apply no such gate: refusals keeps the record a blocked attempt must leave, and wallet_link_lifecycle ceremonies run outside any turn.

The filter matches both conversation and turn because clients supply turn ids. A committed turn in one conversation cannot make another conversation's turn eligible.

Realm and scope apply before query planning

The credential you present fixes the realm: a participant grant names only the conversation tables, a fleet grant names every table. A name outside the realm fails to resolve before execution. The scope inside the grant then admits only the partitions your persona participates in.

What each query scope can read
Queryable dataIn a conversationYour own sessionsAdmin
This conversation's committed turnsReadsReadsReads
Message text and tool argumentsReadsReadsReads
Every conversation you take part inHiddenReadsReads
Someone else's conversationHiddenHiddenReads
Messages never sent to a clientHiddenHiddenReads
Raw signer keys and edge identitiesHiddenHiddenReads
Undecoded event bytes (events_raw)HiddenHiddenReads
Every persona's profile and walletHiddenHiddenReads
ReadsReadsHiddenHidden

Your scope limits which conversations, tables, and columns you can query. A query fails if it names a table or column that your session's catalog does not register.

The verified caller determines the credential. An admin session mints a short-lived fleet-wide grant. A persona session mints a grant over the conversations that person's participation records name.

Tools running within a conversation use its trusted dispatch attribution to determine scope. Their arguments cannot select another conversation.

Participant grants expose the content already available to participants through transcripts and approval interfaces. These categories live in fleet-only tables:

  • Raw signer keys.
  • Identity provenance — who asserted each participant identity on the edge.
  • Rows a turn marks as never sent to a client.
  • Settlement verdicts and routine internals.
  • Deployment-wide persona, credential, and query-audit records.

Queries include full tool arguments and results already available to participants, without display truncation.

How an agent reads its own conversation

Two conversation-history tools use fixed SQL statements and do not require approval. conversation_recent_turns lists committed turns, newest first: 20 by default, at most 50. conversation_list_tool_calls lists recorded calls and argument previews: 20 by default, at most 100. Full-detail mode adds turn-failure information or human-approval status, respectively.

Agents cannot submit raw SQL from within a conversation. Model-authored SQL can combine rows with different trust levels, preventing the result from retaining each row's provenance verdict.

Outside conversations, ad-hoc SQL runs against the standalone Query plane. Your session mints a caller-held grant — POST /api/query/grant for your own conversations, POST /api/query/admin-grant for an admin — and the caller presents it as the bearer on a direct Execute call to the Query edge socket. No Control endpoint accepts SQL; Control only mints the credential.

Shell
curl -sS -X POST https://<control-plane>/api/query/grant \
  -H "authorization: Bearer $POLYCHROME_SESSION"
# → {"token":"…","expires_at_ms":…}

# The grant rides as the bearer on a Connect Execute call to the Query
# edge socket, which streams result frames back:
# POST https://<query-edge>/polychrome.query.v1.QueryService/Execute
#   authorization: Bearer <token>
#   {"sql":"SELECT model, COUNT(*) AS turns FROM model_call GROUP BY model"}

Check truncated before interpreting a result. A true value means the response reached its row limit. Narrow the query or use COUNT(*) to obtain a total.

Query limits

The Query plane parses each statement and checks its type, not its prefix. It accepts exactly one statement, and that statement has to be a query. Data definition, data modification, SHOW, COPY, SET, transaction control, and multi-statement batches are refused before planning. EXPLAIN ANALYZE runs the query, so it is refused everywhere. Plain EXPLAIN is admin-only. Ad hoc external-table references are off for every scope.

LimitDefaultWhen the limit is reached
Wall clock30 secondsThe query returns a timeout rather than holding a request open.
Rows returned10,000The result is cut to the cap and flagged with truncated.
Concurrent executionsDeployment-configuredExecutions beyond the bound wait on a permit; the wall-clock timeout still applies once one starts.
Execution memoryDeployment-configuredQueries share one fair pool, and larger queries spill intermediate data to disk under a quota.
Grant mints, per caller30 a minuteMints exceeding the budget are refused without queueing. A grant is cheap to re-mint, so retry shortly.

Each query records an intent before execution and an outcome afterward in the fleet-only query_audit_* tables. If recording the intent fails, the query does not run. An intent without an outcome indicates that no result was recorded. Fixed-statement conversation tools follow the same audit requirement.

Where the rows come from

The projector replays each journal partition once per generation and writes exact, signed artifacts. A query registers only the artifacts its realm and scope admit, then reads them as ordinary columnar tables — statistics and projection pushdown apply. There is no query-time replay and no decode cache; a new generation republishes an artifact rather than mutating one.

A LIMIT can bound a simple plan. Sorting, grouping, and joins build intermediate results before applying the output limit. Narrowing the conversations your scope admits reduces the artifact set a query opens.

The dashboard and the fixed-statement conversation tools run per-request statements against the fleet realm. No maintained dashboard table exists — the totals come out of the same published artifacts.

The query fact model defines the responsibilities of decoding, shared folds, and consumer projections. It also documents table classes, scope, and redaction rules.