Skip to content

Persona drift detection for edit_soul — baseline anchor built on soul-history (follow-up to #1985 / ADR 0081) #1986

Description

@mabry1985

Follow-up to #1985 (the guarded edit_soul tool, ADR 0081). The due-diligence on that PR found the field's consensus is that versioning + rollback is reactive — it lets a human catch and revert drift but doesn't detect it. The recommended addition is a periodic baseline anchor / drift check. ADR 0081 documents this as a known gap; this issue tracks building it.

Why it's cheap: soul-history already did the hard part

write_soul snapshots every outgoing persona to soul-history (#1691), so we already have — with zero new storage — the two things a drift check needs:

  • a baseline (earliest authored version, or an operator-pinned "known-good" revision), and
  • the full edit trail.

list_soul_versions() / read_soul_version(id) / soul_revision() already expose them. This turns "build a persona-history subsystem" into "add a comparator + a scheduled trigger."

Design

Baseline = earliest soul-history entry, or an operator-pinned revision.

Signals — cheap first, LLM only if enabled:

  • Deterministic (free, no model): edits since baseline, net size delta, section churn (baseline sections dropped / new ones added), % of baseline retained via difflib.SequenceMatcher. Catches silent accretion and "losing sight of the persona."
  • Semantic (opt-in LLM-judge): compare baseline vs current → {drift_score, identity_preserved, doctrine_leak, rationale}. The doctrine_leak field also closes the other feat(persona): guarded edit_soul tool — the agent can refine its own SOUL.md (ADR 0081) #1985 follow-up (the persona-vs-doctrine guard — flag when operating instructions accrete into SOUL, the CLAUDE.md/AGENTS.md bloat failure). One judge covers both.

Altitude: a scheduled curation pass — same lineage as dream/distill (ADR 0054): read-only, runs daily or after every N self-edits.

Surface + remedy — both already exist:

So the whole loop reuses infrastructure: soul-history (baseline + trail), the event bus (surface), the curation-subagent altitude, and the existing restore (remedy).

Open decision

How aggressive the metric is:

  • Deterministic-only — free, no model call, ships fast. Catches accretion/size/section drift.
  • + LLM-judge — also catches semantic drift + doctrine leak, at the cost of a scheduled model call.

Recommendation: start deterministic-only (immediately useful, no cost), add the judge as an opt-in second stage that also subsumes the doctrine-leak guard.

Prior art (from the #1985 due diligence)

  • Hermes's self-evolution repo runs a "semantic preservation — must not drift from original purpose" gate (offline, human-reviewed).
  • Letta added a read-only persona guard after unconstrained self-edits degraded identity.
  • Drift literature (arXiv 2601.04170 "Adaptive Behavioral Anchoring") recommends anchoring to a baseline period.

Scope

Not blocking #1985 (that ships with reactive guards: off-by-default, section-scoped, snapshot+rollback, operator notice). This is the proactive layer on top.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-infoIssue is missing required sections — see CONTRIBUTING.md (silent issue gate).team-readyTriaged and approved for autonomous team dispatch — the ONLY intake gate the board pipeline accepts

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions