v0.7.0rc1 — salience tier Phase 1 + capture attention Phase A
Pre-release
Pre-release
[0.7.0rc1] - 2026-05-22
Fixes
build_standing_set.pyexemplar bias — added declarative-posture
patterns. The pre-fixCONSTRAINT_EXEMPLARSlist leaned heavily
imperative ("never," "always," "must," "default to"). Surfaced
2026-05-22: against the real prod vault the auto-selected top-10
was 100% engineering rules — career / lifestyle / posture
constraints spanning multi-year load-bearing facts (runway,
recruiter posture, start-date framing, job-search mode) did not
surface despite being equally durable, because the user encodes
them declaratively ("Brian's stance," "current preference,"
"passive/selective mode") rather than imperatively. Added 10
declarative-posture exemplars representing the same constraint
class in declarative shape. Exemplar list 22 → 30; imperative /
declarative split now roughly balanced. ROADMAP audit-finding
follow-up perfeedback_audit_findings_become_roadmap_followups.
Operator should re-runscripts/salience_phase0.sh snapshot && scripts/salience_phase0.sh scoreto verify the bias fix surfaces
career-context memories alongside the engineering rules in the
top-10.
Features
- Salience tier Phase 1 — first-class standing-context recall
(default-off, soak-gated). Memories explicitly promoted via
memory_promoteare injected into every<mnemon-context>
envelope on every prompt, regardless of query similarity. The cap
is the contract: default 15, hard ceiling 20. Plan:
private/mnemon-salience-tier-plan-260521.md.- Reframed validation gate (2026-05-22). Phase 1 IS the
validation. Earlier plan called for a synthetic A/B against the
Phase 0 env-var-flagged form before committing to schema +
tooling. Reframed because the injection mechanism is identical
between the two forms — an A/B of the gated env-var path
carries no marginal information once Phase 1 ships gated behind
STANDING_TIER_ENABLED=false. Operator promotes ~5 career-
context memories, flips the flag, observes ≥1 week soak for
runway-style under-weighting recurrence vs absence. Per
feedback_phase_gated_soak_consumer_must_be_ready: ship the
substrate gated, flip activation at a separate milestone. - Schema migration:
documents.tier TEXT NOT NULL DEFAULT 'situational'via_migrate_tier(). Indexidx_documents_tier
on live rows for the cap-count probe + search exclusion filter.
Additive + harmless ifSTANDING_TIER_ENABLEDstays off. Store.promote_to_standing(id)+demote_to_situational(id)list_standing()+standing_tier_status(). Promote
raisesStandingTierCapReachedat the runtime cap,
StandingTierProvenanceRejectedwhen source_client is in
STANDING_TIER_BLOCKED_SOURCE_CLIENTS(Layer 4 composition —
hook-sourced memories cannot be promoted; operator-explicit
gesture only), andStandingTierErroron missing /
invalidated docs. Idempotent re-promote returns True; demote
of a situational doc returns False (no-op).
Store.search_bm25+Store.search_vectorgain
include_standing: bool = Falsekeyword param. Standing-tier
docs excluded from ranked retrieval by default — they're
injected unconditionally already; ranking them too would
double-count and crowd the situational signal. Threaded through
search.search()so the higher-level entry respects the
invariant.- MCP tools:
memory_promote(id),memory_demote(id),
memory_list_standing()— both stdio (server.py) and
Streamable HTTP (server_remote.pyreuses the samemcp
object). 14 → 17 registered tools. - CLI:
mnemon standing list / promote <id> / demote <id>.
mnemon statusgains aStanding tier: N/CAPline. build_contextintegration: whenSTANDING_TIER_ENABLED
(config constant ORMNEMON_STANDING_TIER_ENABLEDenv override,
accepting1/true/yes/on), build_context calls
memory_list_standingvia the remote client in a single
round-trip and renders the result as the "Standing context"
sub-section ahead of "Situational recall." Phase 0 env-var path
(MNEMON_STANDING_TIER_FILE→ standing.json → standing-rendered.md
cache) is preserved as fallback so operators retain a
per-session override mechanism.- Composability invariants (all preserved):
- Layer 0 (
is_well_shaped) — capture rejection runs before
anything reaches the standing-tier promotion path - Layer 1 envelope — standing block sits inside the same
<mnemon-context>data-marking + nonce as situational - Layer 4 (
HOOK_SOURCE_CONFIDENCE_CEILING+ provenance) —
hook-sourced memories cannot be promoted; explicit
StandingTierProvenanceRejectedrejection - rc16
source_keyupsert — unchanged; tier orthogonal - Capture attention Phase A —
recurrence_countaccretes
against canonical situational memories; standing-tier
promotion is operator-gated on top of that signal
- Layer 0 (
- Soak gates for flipping default-on: (a) ≥1 week with the
flag on; (b) observed reduction in runway-style under-weighting
recurrence on real career-strategy conversations; (c) zero
spurious-injection complaints from operator review of every
promoted memory. - 22 new tests in
tests/test_standing_tier.pycovering: promote
success / cap-rejection (cap=2 in test, 3rd raises) /
hook-sourced rejection / invalidated rejection / missing rejection
/ cap respects invalidated (freed slot reclaimable) / demote
round-trip / demote idempotent on situational / demote frees cap
slot / list_standing ordering + content / search excludes by
default / search includes when requested / build_context
flag-off no-fetch / flag-on memory_list_standing call /
env-var truthy value parsing. Suite 814 → 836 passing
(test_server_remote.pytool-count assertions bumped 14 → 17).
- Reframed validation gate (2026-05-22). Phase 1 IS the
Schema
-
documents.tier TEXT NOT NULL DEFAULT 'situational'—
additive migration in_migrate_tier()after the existing
_migrate_recurrence_count. Indexidx_documents_tierscoped to
live rows for cap-count + search-filter queries. -
Capture attention Phase A — recurrence-weighted memory convergence
(default-off, soak-gated). When a new save's content is semantically
close to ≥2 prior memories spanning distinct sessions, capture
attention preserves the new memory + inserts'restates'relations
to each cluster member + boosts the canonical neighbor's confidence- increments the canonical's new
recurrence_countcolumn. The
cluster of restatements stays discoverable; the load-bearing signal
accretes on the canonical; MMR diversity at recall naturally
suppresses near-duplicates without us dropping them at capture.
Plan:private/mnemon-capture-attention-plan-260522.md. Driver: the
2026-05-22 finding that load-bearing facts stated across many
sessions land as fragmented memories rather than a single canonical
assertion (the operator was implicitly substituting for a missing
mechanism).
- SOTA invariant: preserve+relate+boost, never skip-the-save.
Earlier draft considered "boost canonical + skip the new save"
as the auto-apply path — rejected because each restatement
carries different framing and discarding it throws away the very
signal the recurrence detector is honoring. The institutional
pattern is preserve the data, link via relations, accrete the
importance signal — operator-reviewed merge is Phase C of the
plan, not Phase A's job. - Embedding-only (no LLM dependency). Same SOTA-for-public-
release-constraint logic that drovebuild_standing_set.py's
embedding-based scorer (the roadmapped LLM-judge opt-in P2 item
composes as an advanced mode but isn't required). - Feature flag
CAPTURE_ATTENTION_ENABLEDdefault-off through
soak. Two acceptance criteria to flip default-on (per plan
§"Soak acceptance criteria"): (1)boost_rate ≤ 0.25over a 7-day
window measured viamnemon attention-status; (2) ≥80% precision
on a 20-canonical manual review. correction_ofparameter onStore.save()(forward-compat
for salience-tier Phase 2 promotion signals). When set, capture
attention is skipped — operator explicit gesture beats automated
recurrence detection.mnemon attention-statusCLI — soak monitor: boost-rate
ratio over 7 days, recurrence-count distribution, top-10
canonicals, last-10'restates'relations audit trail.scripts/calibrate_capture_threshold.py— data-tuned
threshold selection. Samples N pairs from the operator's vault
snapshot, prompts for same/different tagging, computes
precision-recall at {0.70, 0.75, 0.80, 0.85, 0.90}, recommends
the precision-leaning sweet spot. Persists tagged pairs to
tests/fixtures/capture_attention_pairs.jsonfor regression
locking.- Failure mode: named exception + WARN swallow. Embedder /
vecstore unavailability raisesCaptureAttentionUnavailableError
fromapply_capture_attention();Store.save()catches +
logger.warnings + continues (the new memory is saved; only the
recurrence-boost side effect is skipped). Acceptable swallow per
feedback_no_silent_failscategory (b) — secondary observability
hung off a primary save path that records the failure. - Composes with the existing layered defenses unchanged.
Capture attention runs AFTER Layer 0 (is_well_shapedrejects
scaffolding before the path is reached) + AFTER Layer 4 ceiling
(HOOK_SOURCE_CONFIDENCE_CEILINGclamp survives the boost).
'restates'is a new relation type — doesn't collide with the
existing'supersedes'/'contradicts'/'related'. - 13 new tests in
tests/test_capture_attention.pycovering: the
preserve-everything invariant, feature-flag-off no-behavior-
change, distinct-sessions trigger, same-session no-trigger,
threshold respected, hook ceiling, user uncapped, pinned-canonical
selection,correction_ofoverride, fail-loud on embedder
unavailability, schema migration idempotency. Suite 801 → 814
passing.
- increments the canonical's new
Schema
documents.recurrence_count INTEGER NOT NULL DEFAULT 0—
additive migration in_migrate_recurrence_count(). Pre-existing
rows get count=0 and recurrence detection starts forward from the
next save. Harmless ifCAPTURE_ATTENTION_ENABLEDstays off.