Skip to main content

WarningHint

Enum WarningHint 

Source
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.

Fields

§entity_type: String
§heading: String
§write_rules: Vec<String>
§

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).

Fields

§entity_type: String
§description: String
§enum_values: Vec<String>
§

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.

Fields

§rel_type: String
§message: String
§

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.

Fields

§rel_type: String
§

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.

Fields

§rel_type: String
§

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.

Fields

§allowed: Vec<String>
§

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.

Fields

§requested: usize
§actual: usize
§

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.

Fields

§requested_title: String
§current_slug: String
§

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.

Fields

§title: String
§dropped_chars: Vec<char>
§slug: String
§

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.

Fields

§

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.

Fields

§entity_type: String
§

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_types empty → 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_types non-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

§scoped_type: Option<String>

entity_type the search call scoped to (None for an unscoped call).

§declared_on_other_types: Vec<String>

Types where the filter IS declared, sorted alphabetically. Empty when no reachable schema declares the key at all.

§

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.

Fields

§field: String
§

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.

Fields

§value: String
§

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.

Fields

§value: String
§allowed: Vec<String>
§

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.

Fields

§kept: usize
§total: usize
§

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.

Fields

§kept: usize
§budget: usize
§

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.

Fields

§

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

§field: String
§key: String

The literal filter key the caller sent, e.g. min_count.

§scoped_type: Option<String>
§declared_on_other_types: Vec<String>
§

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.

Fields

§field: String
§

SearchMemIndexUnavailable

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).

Fields

§reason: &'static str

Discriminator: "missing_index" or "query_failed".

§error: Option<String>

The underlying error string when reason == "query_failed"; None for "missing_index".

§

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).

Fields

§original: String
§trimmed: String
§

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

§resolved_id: EntityId
§candidate_target: Option<EntityId>

Stripped-and-resolved candidate via the two-pass resolver (cross-mem lookup first, bare-slug fallback second). None when no real entity was found — the author must disambiguate.

§section: String
§

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.

Fields

§stubs: Vec<EntityId>
§

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).

Fields

§

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)

Fields

§from_mem: String
§to_mem: String
§target_id: EntityId
§

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.

Fields

§tool: String
§

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.)

Fields

§field: String
§supplied: String
§

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).

Fields

§outer_repo_root: String
§workspace_root: String
§

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

§entity_type: String
§entity_id: EntityId
§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.

Fields

§entity_type: String
§entity_id: EntityId
§

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.

Fields

§entity_id: EntityId
§section_key: String
§heading: String
§occurrences: usize
§

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.

Fields

§old_head: String
§new_head: String
§entities_loaded: usize
§

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.

Fields

§stub_id: EntityId
§pending: bool
§

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.

Fields

§rel_type: String
§

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 in strict mode.
  • shape — the (source_type, target_type) pair is not allowed by the rel-type’s source_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

§entity_id: EntityId
§rel_type: String
§target: EntityId
§reason: String
§origin: String
§

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.

Fields

§referrers: Vec<EntityId>
§

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 survived remove_dir_all (filesystem permission, busy handle, …). path names the directory; error carries the OS-level diagnostic.
  • backend_prune_failed — git-branch backend rejected the ref-edit transaction that prunes refs/heads/<branch_leaf> + __MEMSTEAD:mems/.../config.json (gitdir IO, concurrent writer racing the ref). path is None; error carries 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).

Fields

§reason: String
§

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.

Fields

§unregistered_at: String
§

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.

Fields

§mems: Vec<String>
§from_host_mems: Vec<String>
§

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

§stamped_engine: String

Engine version the last mutation was performed under.

§running_engine: String

Engine version of the running binary.

§stamped_schema: String

Resolved schema the last mutation validated against.

§

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

§pinned: String

The pinned ref (name@version).

§newest: String

The newest built-in version registered under the same name.

§

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.

Fields

§

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.

Fields

§schema_ref: String
§stamped_path: String
§mems: Vec<String>
§

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.

Fields

§schema_ref: String
§stamped_path: String
§mems: Vec<String>
§detail: String
§

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

§rel_type: String
§target: EntityId
§trailing: String

Literal trailing content captured between ]] and end of line — surfaced verbatim so the operator can paste the intended text back in with a canonical delimiter.

§

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.

Fields

§rel_type: String
§target: EntityId
§

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.

Fields

§rel_type: String
§target: EntityId
§

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

§mem: String

Mem whose mount expectation and config pin disagree.

§config_pin: String

Authoritative pin from the mem’s per-mem config.

§mount_pin: String

Expectation pin recorded on the workspace mount.

§

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

§entity_id: EntityId
§section_key: String
§writing_heading: String

Heading the mutation is writing (the schema’s declared one).

§existing_heading: String

Different heading the file carried for the same key.

§

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.

Fields

§mem: String

Mem whose pinned schema violates the rule.

§schema_ref: String

The pinned <name>@<version>.

§violations: Vec<SchemaHeadingViolation>

Every offending (type, key, heading, derived_key) tuple.

Implementations§

Source§

impl WarningHint

Source

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.

Source

pub fn message(&self) -> String

Human-readable message — delegates to Display. May change across releases; use WarningHint::code for branching.

Source

pub fn source_mem(&self) -> Option<&str>

Mem that “owns” the warning when one can be attributed. Workspace-/request-scoped variants return Nonememstead_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).

Source

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

Source§

fn clone(&self) -> WarningHint

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WarningHint

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for WarningHint

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Serialize for WarningHint

Source§

fn serialize<S>( &self, serializer: S, ) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts 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>

Converts 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)

Converts &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)

Converts &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
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Send + Sync>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Fruit for T
where T: Send + Downcast,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more