pub enum WarningHint {
Show 51 variants
MissingRequiredSection {
entity_type: String,
key: String,
heading: String,
write_rules: Vec<String>,
},
MissingRequiredField {
entity_type: String,
key: String,
description: String,
enum_values: Vec<String>,
},
UndeclaredRelationshipOpen {
rel_type: String,
message: String,
},
DuplicateRelationship {
rel_type: String,
from: EntityId,
to: EntityId,
},
NoSuchRelationship {
rel_type: String,
from: EntityId,
to: EntityId,
},
UnknownIncludeKey {
key: String,
allowed: Vec<String>,
},
LimitClamped {
requested: usize,
actual: usize,
},
TitleNormalizedToSlugNoop {
requested_title: String,
current_slug: String,
},
TitleCharsDroppedFromSlug {
title: String,
dropped_chars: Vec<char>,
slug: String,
},
UpdateNoop {
id: EntityId,
},
StubFilterExcludesAll {
entity_type: String,
},
UnknownFilterKey {
key: String,
scoped_type: Option<String>,
declared_on_other_types: Vec<String>,
},
FieldNotFilterable {
field: String,
},
FilterValueMultiMember {
key: String,
value: String,
},
FilterValueNotInEnum {
key: String,
value: String,
allowed: Vec<String>,
},
NeighbourhoodCapped {
kept: usize,
total: usize,
},
SearchResultsTruncated {
kept: usize,
budget: usize,
},
RangeFilterKeyMalformed {
key: String,
},
UnknownRangeFilterField {
field: String,
key: String,
scoped_type: Option<String>,
declared_on_other_types: Vec<String>,
},
FieldNotRangeFilterable {
field: String,
},
SearchMemIndexUnavailable {
mem: String,
reason: &'static str,
error: Option<String>,
},
TitleTrimmed {
original: String,
trimmed: String,
},
SuspiciousNestedPrefix {
from: EntityId,
resolved_id: EntityId,
candidate_target: Option<EntityId>,
section: String,
},
InlineWikiLinkAutoStubbed {
from: EntityId,
stubs: Vec<EntityId>,
},
SelfLinkIgnored {
id: EntityId,
},
CrossMemTargetMemUncreated {
from_mem: String,
to_mem: String,
target_id: EntityId,
},
NoteMissing {
tool: String,
},
IgnoredReadonlyField {
field: String,
supplied: String,
},
OuterRepoNotIgnoringMemRepo {
outer_repo_root: String,
workspace_root: String,
},
MissingRequiredOutgoing {
entity_type: String,
entity_id: EntityId,
missing: Vec<MissingRequiredOutgoingBlock>,
},
ConstraintUnsatisfied {
entity_type: String,
entity_id: EntityId,
violations: Vec<UnsatisfiedConstraint>,
},
DuplicateSectionHeading {
entity_id: EntityId,
section_key: String,
heading: String,
occurrences: usize,
},
MemReloaded {
mem: String,
old_head: String,
new_head: String,
entities_loaded: usize,
},
AutoStubCreated {
stub_id: EntityId,
pending: bool,
},
DerivationBaselineRefreshed {
from: EntityId,
rel_type: String,
to: EntityId,
},
ParsedRelationInvalid {
entity_id: EntityId,
rel_type: String,
target: EntityId,
reason: String,
origin: String,
recovery: Option<ParsedRelationRecovery>,
},
ResidualStubForReadOnlyReferrers {
id: EntityId,
referrers: Vec<EntityId>,
},
MemFilesNotDeleted {
mem: String,
reason: String,
path: Option<String>,
error: Option<String>,
},
MemReattachedAfterUnregister {
mem: String,
unregistered_at: String,
},
ReadMemsMigratedToMounts {
mems: Vec<String>,
from_host_mems: Vec<String>,
},
EngineVersionSkew {
mem: String,
stamped_engine: String,
running_engine: String,
stamped_schema: String,
},
SchemaGenerationsBehind {
mem: String,
pinned: String,
newest: String,
},
FolderMemProvenance {
mem: String,
},
SchemaAuthoringSourceMissing {
schema_ref: String,
stamped_path: String,
mems: Vec<String>,
},
SchemaAuthoringSourceDiverged {
schema_ref: String,
stamped_path: String,
mems: Vec<String>,
detail: String,
},
AmbiguousDescriptionDelimiter {
from: EntityId,
rel_type: String,
target: EntityId,
trailing: String,
},
ParseMissingRequiredDescription {
from: EntityId,
rel_type: String,
target: EntityId,
},
ParseDescriptionNotPermitted {
from: EntityId,
rel_type: String,
target: EntityId,
},
SchemaPinMismatch {
mem: String,
config_pin: String,
mount_pin: String,
},
SectionHeadingDivergence {
entity_id: EntityId,
section_key: String,
writing_heading: String,
existing_heading: String,
},
SchemaHeadingRoundtripViolation {
mem: String,
schema_ref: String,
violations: Vec<SchemaHeadingViolation>,
},
}Expand description
Typed non-fatal issue surfaced from engine operations. Serialises as the
uniform { code, message, details } envelope so a generic warning handler
(log sink, UI, alerting) can read code + message without branching on
variant. Display renders the agent-facing text, reachable via
WarningHint::message; per-variant structured fields land under
details, their shape keyed by code.
Shared across CreateResult, RelateResult, and HealthSummary. New
variants are additive; they widen the enum rather than fork a per-site
type so wire-level warning consumers keep a single discriminated union
to branch on. The wire shape matches what envelope produces for the
MCP error channel, so one decoder handles both surfaces.
Variants§
MissingRequiredSection
A required section was empty or missing at create time. Carries
the type and section keys plus the section’s own write_rules
so the agent can self-correct with a follow-up memstead_update.
Type-level write_rules no longer ride per warning — they
ship once at the mutation-response top level on
type_guidance keyed by entity_type (F9). Decoders look up
the guidance via entity_type against the top-level map.
MissingRequiredField
A required metadata field was not supplied at create time and the
schema does not auto-fill the value (no default_value, no
init_timestamp, no auto_timestamp). The entity still lands —
the generator may write an empty / today’s-date placeholder into
the frontmatter — but the warning surfaces the gap so the agent
follows up via memstead_update rather than leaving the entity in a
stuck state. Payload mirrors Self::MissingRequiredSection in
shape so a single decoder handles both. Wire-equivalent shape
with EngineError::RequiredFieldUnset’s details payload, since
the recovery path is the same (read the description / allowed
enum values from the envelope rather than re-fetching the
schema).
UndeclaredRelationshipOpen
An undeclared relationship was admitted because the mem’s schema is in open mode. The caller can still suggest the name be added to the schema vocabulary.
DuplicateRelationship
memstead_relate was asked to add an edge that already exists. The
op is a successful no-op — the warning surfaces what would otherwise
be silent so an agent relying on renames / side-effects can notice
the call didn’t change the graph.
NoSuchRelationship
memstead_relate with remove: true was asked to drop an edge that
wasn’t present. Successful no-op, surfaced so an agent operating on
a stale mental model sees the mismatch.
UnknownIncludeKey
An include key passed to memstead_health was outside the accepted
set. The key is ignored; the allowed list is echoed back verbatim so
an agent with a typo can correct on the next call without opening a
schema doc.
LimitClamped
A paged/bounded parameter exceeded its cap. The cap is authoritative so the op still ran, but the warning surfaces what the caller requested vs. what was served.
TitleNormalizedToSlugNoop
memstead_rename was asked to change the title but normalisation
(lowercase, diacritic-folding, punctuation-strip, hyphen-collapse)
mapped the requested title to the existing slug — so the id is
unchanged and nothing is written to disk. Surfaced so autonomous
skills don’t mistake the silent short-circuit for a successful
cosmetic rewrite.
TitleCharsDroppedFromSlug
The title grammar admits any single-line text, but the slug
alphabet stays narrow — this create/rename derived an id that
dropped one or more title characters (&, ., §, …). The
entity lands with the verbatim title; the warning keeps the
title↔id divergence visible without being fatal, naming each
distinct dropped character and the derived slug.
UpdateNoop
memstead_update produced a post-mutation entity whose regenerated
markdown is bytes-identical to the on-disk content — no field,
section, metadata value, relation, or auto-timestamp actually
changed. The op is a successful no-op: no disk write, no
commit, content_hash unchanged. Surfaced so autonomous skills
branching on commit_sha != "" see an explicit signal, and
expected_hash-based polling stays stable across the no-op.
Mirrors TitleNormalizedToSlugNoop for the rename surface.
StubFilterExcludesAll
memstead_search was called with both stub=true and entity_type
set. Stubs carry no entity_type (they are ID-only placeholders),
so the combined filter excludes every stub — the call is an empty
set by construction. Surfaced so an agent doesn’t interpret the
empty result as “no stubs of this type exist” when in fact no
stub can ever satisfy the filter. Drop entity_type to list stubs.
UnknownFilterKey
memstead_search(filters: {<key>: ...}) named a filter key that the
queried type does not declare. The wire code() discriminates
the two outcomes, so a consumer branches on code alone:
declared_on_other_typesempty → no reachable schema declares the key →UNKNOWN_FILTER_KEY; the filter is truly ignored and the result set equals the same search without it.declared_on_other_typesnon-empty → the key is declared on other type(s) and the filter was applied with strict type-narrowing (result restricted to the declaring type(s), or emptied when the call scoped to a non-declaring type) →FILTER_TYPE_SCOPED.
declared_on_other_types stays on the wire as enrichment, not as
the disambiguator.
Fields
FieldNotFilterable
memstead_search(filters: {<field>: ...}) named a field that the
schema declares but with filterable: none — the filter is
ignored, the hit set is unconstrained by it.
FilterValueMultiMember
memstead_search(filters: {<csv-field>: "a,b"}) passed a comma-bearing
value to a csv-array field. csv fields match a single member, so
the whole rendered value (e.g. the tags: dedup,retry an entity
displays) can never equal any one member — the filter matches
nothing. Surfaced so an agent that copied the rendered value gets a
recoverable signal (split into repeated single-member filters)
rather than an empty result indistinguishable from a true
no-match. The filter still applies as written (matches nothing);
this only adds the advisory.
FilterValueNotInEnum
memstead_search(filters: {<field>: <value>}) passed a value the
schema field constrains with an enum_values allow-list, but the
value (or, for a csv-array field, one of its comma members) is not a
member. The filter still applies as written and matches nothing for
that value, so an empty result is otherwise indistinguishable from a
true no-match — this surfaces the typo plus the allowed values so an
agent corrects without opening the schema. Reuses the
INVALID_ENUM_VALUE code from the mutation surface.
NeighbourhoodCapped
memstead_search(related_to: <id>) reached a neighbourhood larger
than the cap. The results were ranked by proximity (nearer first)
and bounded to the nearest kept of total reachable entities so a
hub can’t flood the caller. Surfaced so the agent knows the
neighbourhood was truncated — narrow with depth/filters for more.
SearchResultsTruncated
memstead_search trimmed the returned page to fit the token budget.
The highest-ranked kept hits that fit under budget are returned;
the rest of the page is dropped so the response stays under the MCP
transport cap. _total still reflects the full match count — page the
remainder with offset, narrow the query, or raise token_budget.
RangeFilterKeyMalformed
memstead_search(range_filters: {<key>: ...}) named a key that
doesn’t follow the min_<field> / max_<field> / <field>_before
/ <field>_after grammar. The key is ignored.
UnknownRangeFilterField
memstead_search(range_filters: {<key>: ...}) named a range-filter
key whose underlying field the queried type does not declare.
Same shape and same one-code-per-outcome split as
Self::UnknownFilterKey: code() is UNKNOWN_RANGE_FILTER_FIELD
when declared_on_other_types is empty (truly ignored, result =
unfiltered) and RANGE_FILTER_TYPE_SCOPED when non-empty (applied
with strict type-narrowing). Includes the literal key (the
prefixed/suffixed form the caller sent) alongside the bare field.
Fields
FieldNotRangeFilterable
memstead_search(range_filters: {<field>: ...}) named a field that
the schema declares but with a filterability other than range.
The range filter is ignored.
memstead_search could not query a target mem’s search index —
either the mem has no index yet (reason: "missing_index")
or a tantivy execution failure surfaced (reason: "query_failed" plus the error string).
TitleTrimmed
memstead_create (or memstead_rename) received a title with leading
or trailing whitespace. The engine silently strips the surround
before slug derivation and storage; the warning records what the
caller sent vs. what landed so the audit trail can spot the
drift. Internal whitespace (between words) is preserved
untouched. Fully-whitespace titles are still refused at the
validator boundary (those collapse to empty).
SuspiciousNestedPrefix
An inline wiki-link resolved to an ID of the form
<current-mem>--<other-known-mem-suffix>--<slug>. This is
almost always drift from a mem-rename — the author wrote
[[plugin--slug]] expecting plugin to be the mem prefix, but
the current mem is test-mem-plugin, so the literal
resolution nests the prefix. Detection only — the load path still
creates the stub (no silent rewrite). Fix via memstead_update patch_sections to either the bare slug or the fully-qualified ID.
Emitted at load / reload / attach time and carried through
HealthSummary.warnings; mutation paths never emit this warning
to avoid noise on every edit.
Fields
InlineWikiLinkAutoStubbed
Inline [[wiki-link]] syntax in entity section bodies parsed to
targets that did not yet resolve, so the engine auto-created stub
entities for them. A common authoring hazard: an agent illustrating
link syntax in prose ([[example:slug]]) inadvertently creates
ghost stubs and a REFERENCES edge from the prose entity to each.
Surfaced so the agent reviews the list and either replaces the
inline literal with a fenced/quoted form or removes the entity if
the stub was not intended. Carries the source entity id (from)
and every newly-stubbed target id created by THIS call.
SelfLinkIgnored
A body wiki-link resolved to the entity’s own id, so the
alias-synthesis pass dropped the would-be self-referential edge
(F11) — a self-edge carries no navigational value and would render
as both an Outgoing and an Incoming neighbour of itself. The
create/update still succeeds (the author may have written their
own slug); this warns so the dropped link is observable, matching
the alias pass’s other side-effect warnings (AUTO_STUB_CREATED /
INLINE_WIKI_LINK_AUTO_STUBBED).
CrossMemTargetMemUncreated
memstead_relate to a cross-mem target whose mem is not (yet)
mounted in the workspace. The cross-mem link policy permits
the edge, so the engine auto-stubs the target as a forward
reference — but with the target mem entirely absent from
writable_mems(), the stub has no _mem_schema resolution
and any later read sees an indeterminate-schema entity. The
warning makes the missing-mem state visible so an operator
can distinguish a typo (intended B but typed b) from a
deliberate forward reference that expects the mem to be
created later. (F4)
NoteMissing
A mutation landed without a note field while the workspace
config’s [mutations].require_notes = true — provenance is
best-effort, so the engine completes the commit but flags the
absence so autonomous skills can audit their coverage. The
mutation still writes to disk and produces a commit; this warning
exists purely to surface the missed opportunity for a human- /
agent-readable body line. tool carries the MCP tool name
(memstead_create, memstead_update, …) so consumers can attribute the
gap without re-deriving it from the response context.
IgnoredReadonlyField
A create supplied a value for an auto-managed metadata field
(init_timestamp like created_date, or auto_timestamp like
last_modified); the engine owns those values, so the supplied
one was discarded and the engine value stamped instead. The
entity still lands — this warning closes the silent-drop gap so
the agent learns its input had no effect without a follow-up
read. field names the discarded key; supplied echoes the
rejected value. (The memstead_update path refuses the same keys
outright with READ_ONLY_FIELD; create’s posture is
stamp-and-proceed, so it warns rather than refusing.)
OuterRepoNotIgnoringMemRepo
The workspace is embedded inside another git repository
(outer_repo_root) whose .gitignore does not list
mem-repo/. Without that ignore line, the outer repo would
either swallow mem-repo-git as a nested untracked tree or
(worse) record it as a submodule via gitlink — both shapes
silently corrupt the mem-repo identity.
Surfaced from memstead_health so the agent / operator can fix
the outer repo’s .gitignore (or pass --no-gitignore at
memstead mem-repo init/migrate-from-disk time and accept the
risk explicitly).
MissingRequiredOutgoing
One or more required_outgoing blocks on the entity’s type are
not yet satisfied by its post-application outgoing edges. Tier-2
— the create/update lands; the warning surfaces every unsatisfied
block in a single payload so the agent can emit one batched
memstead_relate follow-up.
Fields
missing: Vec<MissingRequiredOutgoingBlock>Each entry mirrors one unsatisfied RequiredOutgoing block:
the alternative relationship names plus the rendered
cardinality literal ("at_least_one").
ConstraintUnsatisfied
The written entity violates warn-tier declared constraints
of its type (e.g. requires_when: a field required under the
current value of another field is unset). Block-tier violations
refuse instead ([EngineError::ConstraintUnsatisfied]) — the
warning only ever carries severity: warn entries.
DuplicateSectionHeading
A markdown file declared the same ## <Heading> twice or more for a
schema-declared section key. The parser keeps the first occurrence’s
body and drops the rest — the duplicate headers and their bodies are
removed from the storage value, so the next read-modify-write cycle
emits a single heading. Surfaced so the operator (or the next ingest
cycle) sees that content was discarded; common cause is an agent
appending a section instead of replacing it.
Emitted at load / reload / attach time only; mutation paths do not re-parse the just-written file.
MemReloaded
The engine detected that a sibling writer (another Engine
instance, an out-of-band git pull, etc.) advanced the on-disk
HEAD of mem past the engine’s cached last_known_head, so
the engine reloaded that mem’s slice of the in-memory store
before serving the current call. The response carries fresh
content; the warning explains why state shifted under the
caller. Agents that need the per-entity diff call
memstead_changes_since with the supplied old_head.
AutoStubCreated
memstead_relate add path landed on a not-yet-real target id and
the engine materialised a stub at that id (in-memory upsert; the
file lands when a follow-up memstead_create promotes the stub).
Pre-fix surfaced through a top-level stub_warning: Option<String>
field on the relate response — agents iterating warnings[] to
surface non-fatal findings silently skipped the auto-stub case.
Carries the materialised stub id so the agent can pin a
follow-up memstead_create (or memstead_relate remove=true to drop
the edge before authoring). pending marks the dry-run path:
the rehearsal validated the add and REPORTS the would-be stub
without writing it — the code stays AUTO_STUB_CREATED
(response-shape stability), only the message branches, so a
rehearsed response never claims a performed effect.
DerivationBaselineRefreshed
A duplicate-add memstead_relate on a derivation-declared
rel-type refreshed the edge’s baseline (agent-trust plan 12) —
the agent’s explicit “I have reviewed the target’s change; the
derivation still holds”. Sidecar-only: _hash unchanged, the
edge unchanged; the response carries this warning so the
refresh is stated rather than a bare no-op.
ParsedRelationInvalid
A relation parsed from an entity’s ## Relationships section
at load time failed validation against the source mem’s
schema (or wiki-link grammar). The entity itself loads
normally; the offending relation is dropped from the
in-memory store. reason discriminates:
unknown_rel_type— the rel-type is not declared in the source mem’s schema and the schema is instrictmode.shape— the(source_type, target_type)pair is not allowed by the rel-type’ssource_types/target_types.cycle— adding this relation would close a cycle in an acyclic-declared subgraph (emitted by the post-load second-pass cycle check; not yet implemented).
Hand-edits, external tooling, and the macOS app’s editor
surface can inject relations that bypass memstead_relate; the
parse-path validation catches those. Mutation-path writes
pre-validated by the engine never trip this warning.
origin discriminates the source mount’s capability:
"writable" (the operator can fix the source markdown via
memstead_update / memstead_relate and re-run) or "readonly"
(the source mem is mounted read-only — purely diagnostic,
the operator either uninstalls the archive or accepts the
dropped relation).
recovery carries an abstract-action payload sufficient to
reverse the drop without consulting another response. Some
when origin == "writable" — the engine can rewrite the
source markdown via the mutation surface, so a consumer (an
agent walking memstead_health, a bulk-fix orchestrator, the
macOS app’s drift panel) maps kind to the concrete call on
whichever MCP / CLI / UniFFI surface it uses. None when
origin == "readonly" — the source markdown is not reachable
via the engine, so no abstract action exists; the warning’s
message names the operator-level path (uninstall the archive
or accept the drop).
Fields
recovery: Option<ParsedRelationRecovery>ResidualStubForReadOnlyReferrers
memstead_delete (or memstead_rename, when implemented) on a
Write-Mem entity that had no Write-Mem referrers but
does have ReadOnly-mount referrers. The on-disk file is
removed and committed; the in-memory entity is demoted to a
stub at the same id so the surviving incoming edges from the
ReadOnly mount(s) keep a valid target. The agent sees
memstead_entity <id> returning a stub immediately and not
stale data after a server reload — fresh boot from disk
reconstructs the same stub via the parser’s auto-stub-on-
unresolved-link path. referrers carries the surviving
ReadOnly source ids so the agent can either accept the stub
or uninstall the archive.
MemFilesNotDeleted
memstead_mem_delete was called with delete_files: true but
at least one part of the symmetric cleanup did not complete.
The mem is already unregistered from the router; this
warning surfaces what survived so an agent reading
files_deleted: false doesn’t trigger redundant cleanup or
blame the wrong layer. reason discriminates:
rmdir_failed— folder-backed mem directory survivedremove_dir_all(filesystem permission, busy handle, …).pathnames the directory;errorcarries the OS-level diagnostic.backend_prune_failed— git-branch backend rejected the ref-edit transaction that prunesrefs/heads/<branch_leaf>+__MEMSTEAD:mems/.../config.json(gitdir IO, concurrent writer racing the ref).pathisNone;errorcarries the wrapped backend message.
One emission per failed step — both can land in the same
response when a folder mount somehow has both an rmdir
failure and a backend cleanup failure (rare; the folder
backend’s delete_artifacts is a no-op default).
MemReattachedAfterUnregister
memstead mem init detected a pre-existing branch + config
blob carrying the unregistered_at tombstone marker that
memstead mem unregister writes — the operator’s deliberate
“preserve for re-attach” signal. The create path adopted the
residual entities, cleared the tombstone, and registered the
branch as a writable mount. Audit visibility for the
reattach so an agent reading the warnings sees what shape
the new mount took. unregistered_at carries the ISO-8601
timestamp the tombstone recorded so the operator can correlate
the reattach with a prior unregister event.
ReadMemsMigratedToMounts
One-time boot migration: legacy readMems entries found in a
writable mem’s config were converted into workspace-level
read-only mounts and the legacy key was removed from the
config. mems lists the migrated read-mem names,
from_host_mems the writable mems whose configs carried them.
A second boot is silent — the source key is gone.
EngineVersionSkew
Boot-honesty skew: the mem’s engine-owned mutation stamp
(MemConfig.mutation_stamp, written after mutations) records a
different engine version than the running binary. Informative,
never fatal — the next mutation under this binary re-stamps.
Absence of a stamp (a pre-stamp mem) never fires this; only a
present, disagreeing stamp does. Surfaces on boot output and
memstead health without an include gate.
Fields
SchemaGenerationsBehind
Generation-behind hint: the mem’s pinned schema resolved from
the BUILT-IN catalogue and the catalogue registers at least
one strictly-higher version of the same name (real semver
ordering). Warn-tier, ungated, never blocking — retention
seals every shipped version, so the pin keeps working; the
hint names the newest available generation and the migration
verb. Locally-installed (workspace-storage) pins are silent:
the engine only knows generations for built-ins. Surfaces on
boot output and memstead health without an include gate,
like the skew hint above.
Fields
FolderMemProvenance
The mem was created on storage with no version control (a
folder mount). Provenance means something WEAKER there than the
headline “every mutation a reasoned commit”: mutations ARE
recorded — each lands in the folder backend’s changelog ledger
(.memstead/changelog.jsonl) with its provenance note — but
there are no commits, the commit_sha every mutation returns
is a synthetic placeholder, and the content is not durable
until the surrounding repository commits it. Emitted once, at
creation, to whoever is actually acting; never a refusal —
folder mems are a supported storage class.
SchemaAuthoringSourceMissing
Authoring-drift health axis: a pinned schema’s sealed copy
carries an install-provenance stamp, and the authoring path it
names is GONE from the working tree. Distinct from
WarningHint::SchemaAuthoringSourceDiverged — a missing
package and a diverged one need different actions. Only
stamped schemas are checked: on git-branch workspaces the
authoring folder is typically absent for unstamped seals, so a
naive existence check would warn on healthy workspaces.
SchemaAuthoringSourceDiverged
Authoring-drift health axis: the stamped authoring path exists
but its package no longer parses EQUIVALENT to the sealed copy
the engine runs on (parsed-schema comparison, never raw bytes —
editor-header comment lines and serialisation reordering do not
trip it). detail says how: a load failure’s message, or the
parsed-difference marker.
AmbiguousDescriptionDelimiter
A ## Relationships row was followed by trailing content that
did not match the canonical em-dash delimiter (—, U+2014
framed by spaces) — ASCII --, ASCII -, en-dash U+2013, or
minus U+2212. The relation parses with description: None;
the trailing content is NOT preserved on the in-memory
Relationship, so the next render of this entity normalises
the row to the simple form - **TYPE**: [[X]]. The warning is
the operator’s signal that content was dropped — restore the
description with an explicit em-dash if it should round-trip.
Emitted at parse time (load / reload / attach); mutation paths
never trip it because they go through the typed description
parameter rather than markdown text.
Fields
ParseMissingRequiredDescription
Parse-time variant of crate::EngineError::MissingRequiredDescription.
A hand-edited ## Relationships row used a rel-type whose
schema declares per_edge_description: required without a
trailing description. The relation still loads (the engine
does not block the file from booting), but the warning
surfaces the gap so the operator follows up with memstead_update
/ memstead_relate to author the missing description.
ParseDescriptionNotPermitted
Parse-time variant of crate::EngineError::DescriptionNotPermitted.
A hand-edited ## Relationships row used a rel-type whose
schema declares per_edge_description: forbidden together
with a trailing em-dash description. The relation still loads
(the engine does not block the file from booting); the
description is dropped from the in-memory Relationship and
the next render normalises the row to the simple form. The
warning surfaces the violation so the operator either removes
the text from disk or asks the schema author to widen the
rel-type’s posture.
SchemaPinMismatch
A mem’s Mount.schema expectation (the pin recorded in the
workspace mounts.json) disagreed with the authoritative pin in
the mem’s own per-mem config. Boot resolves the effective
schema from the mem config (authoritative — a copied/cloned
mem is self-resolvable); this warning surfaces the discrepancy
so neither value is silently dropped. Recovery: align the
mounts.json entry to the mem’s config, or correct the config.
Fields
SectionHeadingDivergence
A mutation wrote a section whose emitted heading differs from a heading already present in the file that derives to the same section key. The write still commits — refusing would strand entities written before the round-trip gate existed — but the divergence is surfaced so the caller sees the file’s heading text shifting under it (the regenerated file carries the schema’s declared heading; the previous text is replaced).
Fields
SchemaHeadingRoundtripViolation
A mem’s resolved (already-installed) schema declares one or
more sections whose heading does not derive back to its key —
the condition new installs are refused for
(check_section_heading_roundtrip). Sealed schemas keep
loading by contract (refusing at boot would brick the
workspace), so the violation surfaces here instead: every write
against such a section forks its content into a second heading
or the catch-all. Recovery: fix the schema’s heading/key pairs
and reinstall.
Implementations§
Source§impl WarningHint
impl WarningHint
Sourcepub fn code(&self) -> &'static str
pub fn code(&self) -> &'static str
Stable UPPER_SNAKE_CASE identifier. Wire-level contract — never rename
an existing value; new variants add new codes. Agents branch on this,
not on WarningHint::message.
Sourcepub fn message(&self) -> String
pub fn message(&self) -> String
Human-readable message — delegates to Display. May change across
releases; use WarningHint::code for branching.
Sourcepub fn source_mem(&self) -> Option<&str>
pub fn source_mem(&self) -> Option<&str>
Mem that “owns” the warning when one can be attributed.
Workspace-/request-scoped variants return None — memstead_health’s
mem filter keeps those visible regardless of scope, while
mem-attributable variants drop out when the filter doesn’t
match. The contract mirrors the data fields the same filter
gates (counts, distributions, detail lists are source-mem
scoped; rosters stay global).
Sourcepub fn all_samples() -> Vec<WarningHint>
pub fn all_samples() -> Vec<WarningHint>
One representative of every WarningHint variant — the single
source of truth consumed by stability tests (envelope_*,
code_values_are_upper_snake_case) and by the MCP description
drift-guard (every_warning_code_appears_in_a_description).
Adding a new variant without extending this list fails those tests;
that’s the forcing function.
Trait Implementations§
Source§impl Clone for WarningHint
impl Clone for WarningHint
Source§fn clone(&self) -> WarningHint
fn clone(&self) -> WarningHint
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 WarningHint
impl Debug for WarningHint
Source§impl Display for WarningHint
impl Display for WarningHint
Source§impl Serialize for WarningHint
impl Serialize for WarningHint
Source§fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
Auto Trait Implementations§
impl Freeze for WarningHint
impl RefUnwindSafe for WarningHint
impl Send for WarningHint
impl Sync for WarningHint
impl Unpin for WarningHint
impl UnsafeUnpin for WarningHint
impl UnwindSafe for WarningHint
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,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<T> Fruit for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more