Safe, structured diagnostics for workspace binding and runtime rejections.
When the server refuses to bind or run a thread's workspace, the user sees
only a one-line refusal. This module defines the small, explicitly allowlisted
comparison snapshot persisted beside each durable binding (so a later refusal
can name what changed) and the structured diagnostics carried by
WorkspaceConflictError, the workspace HTTP route, and the TUI.
The snapshot allowlist is the security boundary: only policy fields whose values are booleans, integers, tool-name/command allowlists, or short enum-like identifiers may be recorded and reported. Model parameters, model specs, profile overrides, system prompts, environment values, credentials, and paths (which can embed user names or project structure) are never persisted or logged — and never hashed as a reporting workaround.
Extract the allowlisted, reportable policy snapshot from a payload.
Build the snapshot persisted with a workspace binding.
Compare a persisted snapshot against the current one.
Fields present in the snapshots are compared with values; fields named in
changed_names (e.g. fingerprint-only or path-valued fields detected by a
fingerprint comparison) are reported as changed without values.
Join Content lines with newlines (Content.join is instance-level).
Render workspace refusal diagnostics as markup-safe TUI content.
Every dynamic value (field names, allowlisted values) flows through
Content.from_markup $var substitution, so square brackets in a value
can never break Rich markup parsing.