pub struct UserConstitution {
pub schema_version: u32,
pub language: Option<String>,
pub about: Option<String>,
pub working_style: Vec<String>,
pub priorities: Vec<String>,
pub autonomy_preference: AutonomyPreference,
pub notes: Option<String>,
pub clauses: Vec<ConstitutionClause>,
pub extra: BTreeMap<String, Value>,
}Expand description
Structured user-global constitution. All content fields are optional so a minimal file still parses and a future schema stays forward-compatible.
Fields§
§schema_version: u32§language: Option<String>Language the prose is authored in (BCP-47-ish tag, e.g. "en",
"zh-Hans"). Localization metadata only.
about: Option<String>Short description of who the user is / their working context.
working_style: Vec<String>Preferred working style / communication preferences.
priorities: Vec<String>Standing priorities or values to weigh across projects.
autonomy_preference: AutonomyPreferenceAutonomy preference — model-facing guidance only.
notes: Option<String>Bounded free prose. Advisory; never parsed as enforceable policy.
clauses: Vec<ConstitutionClause>Individually addressable standing rules (schema v2). Only clauses with
ClauseStatus::Accepted are rendered into the model-facing block.
extra: BTreeMap<String, Value>Unknown top-level fields, preserved verbatim across load/migrate/save so a newer Codewhale’s file survives a round-trip through an older one.
This map is cleared on the untrusted-draft path
(UserConstitution::from_untrusted_json) and is outside
cache_projection, so it can never
reach the prompt or invalidate the prompt cache.
Implementations§
Source§impl UserConstitution
impl UserConstitution
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
True when the constitution carries no usable content (so callers can skip
emitting an empty block and classify it as ConstitutionValidity::Empty).
Suggested clauses do not count: a file that only holds unratified model advice has no law in it yet, and must not be reported as configured.
Sourcepub fn accepted_clauses(&self) -> impl Iterator<Item = &ConstitutionClause>
pub fn accepted_clauses(&self) -> impl Iterator<Item = &ConstitutionClause>
Accepted (ratified) clauses in stable id order. This is the only clause view the renderer and the cache projection may use.
Sourcepub fn suggested_clauses(&self) -> impl Iterator<Item = &ConstitutionClause>
pub fn suggested_clauses(&self) -> impl Iterator<Item = &ConstitutionClause>
Clauses still awaiting ratification, in stable id order.
Sourcepub fn validity(&self) -> ConstitutionValidity
pub fn validity(&self) -> ConstitutionValidity
Classify validity for the setup-state record.
Sourcepub fn bounded(&self) -> Self
pub fn bounded(&self) -> Self
Return a bounded copy: list fields capped to MAX_LIST_ITEMS items of
MAX_ITEM_LEN chars, prose capped to its limit, blank entries dropped.
Free prose is never expanded into structure — it is only length-limited.
Sourcepub fn render_body(&self) -> String
pub fn render_body(&self) -> String
Deterministic, source-path-independent render of the constitution body.
This is the canonical content hashed by preview_hash.
Envelope-tag sequences are neutralized here unconditionally, so even a
hand-edited constitution.json that bypassed the untrusted-draft gate
cannot forge or close the <codewhale_user_constitution> envelope at
render time. Neutralization happens before hashing, so the preview hash
still matches the rendered form byte-for-byte.
Sourcepub fn render_block(&self, source: Option<&Path>) -> Option<String>
pub fn render_block(&self, source: Option<&Path>) -> Option<String>
Render the full model-facing <codewhale_user_constitution> block.
source is included as an attribute for provenance but does not affect
the body or the preview hash. Returns None when empty.
Sourcepub fn preview_hash(&self) -> String
pub fn preview_hash(&self) -> String
Stable content hash (FNV-1a 64-bit, hex) of the rendered body. Used for preview/version tracking in the setup-state record. Deterministic across platforms and independent of the home path.
Sourcepub fn path() -> Result<PathBuf>
pub fn path() -> Result<PathBuf>
Path to the structured user-global constitution under $CODEWHALE_HOME.
Sourcepub fn load() -> Result<UserConstitutionLoad>
pub fn load() -> Result<UserConstitutionLoad>
Load the structured constitution from the home file, classifying the outcome so callers can record validity without re-reading the file.
Sourcepub fn load_from(path: &Path) -> UserConstitutionLoad
pub fn load_from(path: &Path) -> UserConstitutionLoad
Load from an explicit path (testable).
Sourcepub fn save(&self) -> Result<()>
pub fn save(&self) -> Result<()>
Atomically persist the bounded form to the home file. Callers invoke this only on accept — preview must never reach this path.
Sourcepub fn save_to(&self, path: &Path) -> Result<()>
pub fn save_to(&self, path: &Path) -> Result<()>
Atomically persist the bounded form to an explicit path (testable).
Sourcepub fn from_untrusted_json(raw: &str) -> UntrustedDraftParse
pub fn from_untrusted_json(raw: &str) -> UntrustedDraftParse
Parse an untrusted draft (e.g. model output) into a bounded, sanitized constitution.
This is the single ingestion gate for text CodeWhale did not author:
- Extracts balanced JSON objects in order until one parses, so fenced
or prose-wrapped output still parses — including prose that itself
contains braces before the real draft. Anything without a parseable
object is
Invalid, and every drop is logged loudly (#5169). - Unknown keys are ignored by serde, so a draft cannot smuggle
runtime-policy fields (
approval_policy,sandbox_mode, …) into the persisted file — the schema simply has nowhere to put them. - Every text field is stripped of control characters and of
<codewhale_user_constitutiontag sequences, so a draft cannot forge or close the prompt-injection envelope. - The result is
boundedbefore it is returned, so oversized drafts are truncated before preview/save, and the preview hash of what the user ratifies matches what is persisted.
Sourcepub fn cache_projection(&self) -> CacheProjection
pub fn cache_projection(&self) -> CacheProjection
The exact bytes this constitution contributes to the cache-stable prompt prefix, plus their digest and measures (#4782, #3928).
Byte-stability contract, relied on by the prompt-cache accounting:
- it is a pure function of the accepted content only;
- recording a suggestion, preserving an unknown field, or bumping the schema version does not change a single byte;
- it is independent of the home path and of field/clause file order.
Sourcepub fn migrate_raw(raw: &str) -> MigrationOutcome
pub fn migrate_raw(raw: &str) -> MigrationOutcome
Deterministically migrate raw constitution bytes to the current schema.
Pure: no I/O, no clock, no home lookup. Same bytes in, same outcome out.
Sourcepub fn migrate_file(path: &Path) -> Result<MigrationOutcome>
pub fn migrate_file(path: &Path) -> Result<MigrationOutcome>
Migrate the file at path in place, writing a rollback backup first.
A rejection writes nothing at all: the original file is left byte-identical so the user can inspect it, and the receipt says exactly why.
Sourcepub fn rollback_file(path: &Path) -> Result<PathBuf>
pub fn rollback_file(path: &Path) -> Result<PathBuf>
Restore the pre-migration bytes written by Self::migrate_file.
Fails loudly when no backup exists rather than leaving the caller to believe a rollback happened.
Sourcepub fn with_recommendation(
&self,
recommendation: &ConstitutionRecommendation,
) -> Self
pub fn with_recommendation( &self, recommendation: &ConstitutionRecommendation, ) -> Self
Record model advice as suggestions only.
The returned constitution has byte-identical accepted content — asserted by the equal cache digest — so calling this can never change what the model reads next turn. This is the whole “never silently apply model advice” contract in one function (#3930).
Sourcepub fn ratify(
&self,
reviewed_digest: &str,
clause_ids: &[String],
note: Option<&str>,
) -> Result<Ratification, RatificationError>
pub fn ratify( &self, reviewed_digest: &str, clause_ids: &[String], note: Option<&str>, ) -> Result<Ratification, RatificationError>
Ratify specific suggested clauses, failing closed on stale input.
reviewed_digest is the CacheProjection::digest of the base the human
actually reviewed. If the live base has moved since — another save, a
migration, a concurrent edit — this returns
RatificationError::StaleBase and accepts nothing, because the human
approved a document that no longer exists.
Trait Implementations§
Source§impl Clone for UserConstitution
impl Clone for UserConstitution
Source§fn clone(&self) -> UserConstitution
fn clone(&self) -> UserConstitution
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for UserConstitution
impl Debug for UserConstitution
Source§impl Default for UserConstitution
impl Default for UserConstitution
Source§impl<'de> Deserialize<'de> for UserConstitution
impl<'de> Deserialize<'de> for UserConstitution
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for UserConstitution
Eq is asserted by hand rather than derived, because the preserved-unknown
map holds serde_json::Value, which is only PartialEq.
The one value that would break reflexivity is a JSON float NaN — and JSON
cannot express one: serde_json refuses to parse or emit NaN, so no
constitution file can contain a value that is unequal to itself. Downstream
types (UserConstitutionLoad, setup state, TUI drafts) keep their derived
Eq as a result.
Source§impl PartialEq for UserConstitution
impl PartialEq for UserConstitution
Source§impl Serialize for UserConstitution
impl Serialize for UserConstitution
impl StructuralPartialEq for UserConstitution
Auto Trait Implementations§
impl Freeze for UserConstitution
impl RefUnwindSafe for UserConstitution
impl Send for UserConstitution
impl Sync for UserConstitution
impl Unpin for UserConstitution
impl UnsafeUnpin for UserConstitution
impl UnwindSafe for UserConstitution
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.