fix(config): the scheduled-consolidation default includes "mature" - #211
Merged
acidkill merged 1 commit intoSep 7, 2026
Conversation
MaintenanceConfig's default strategy tuple was ("prune", "merge", "enrich").
`mature` is the strategy that owns the EPISODIC to SEMANTIC transition —
ConsolidationStrategy.MATURE dispatches to _mature, which is the only place
that transition happens — so leaving it out meant a deployment on the defaults
never promoted anything.
That matters most for `smem serve`, whose `_consolidation_loop` is a plain
background task with no operation-triggered `auto_consolidate` to fall back on:
if the scheduled pass does not mature, nothing does, and the brain accumulates
episodic memories indefinitely without ever erroring.
Both the field default and the `from_dict` fallback are changed, because the
HTTP daemon rebuilds MaintenanceConfig from a dict on every reload and would
otherwise pick the old tuple straight back up. `docs/reference/config.md` is
generated from the field defaults and follows.
Order is not significant here: the engine groups strategies into
STRATEGY_TIERS, a tuple of frozensets, and runs them tier by tier rather than
in the order the config lists them. "mature" is placed between "merge" and
"enrich" for readability, nothing more.
Two assertions in tests/unit/test_scheduled_consolidation_handler.py already
pinned the old tuple and are updated; a new test asserts "mature" is present
via both the field default and the from_dict fallback, so a regression to a
non-maturing default fails loudly rather than quietly.
acidkill
approved these changes
Sep 7, 2026
acidkill
left a comment
Owner
There was a problem hiding this comment.
Reviewed the full diff. Adding 'mature' to the scheduled-consolidation default fixes the silently non-maturing HTTP daemon; both the field default and the from_dict fallback are pinned by tests. Py3.11 rerun green (it was the #226 hash-seed flake).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MaintenanceConfig's default scheduled-consolidation strategies now includemature, in the field default and in thefrom_dictfallback.docs/reference/config.mdfollows, since it is generated from those defaults.maturethrough both paths.Why
The default tuple was
("prune", "merge", "enrich").matureis the strategy that owns the EPISODIC to SEMANTIC transition —ConsolidationStrategy.MATUREdispatches to_mature, which is the only place that transition happens — so the scheduled pass on the defaults never promoted anything. The MCP server's own consolidation defaults do includemature, so a deployment driven through MCP still matures; the gap is specific to whatever relies on the scheduled pass.That matters most for
smem serve. Its_consolidation_loopis a plain background task with no operation-triggeredauto_consolidatebehind it, so if the scheduled pass does not mature, nothing does. The brain accumulates episodic memories indefinitely and nothing errors, which is why this is easy to run into and hard to notice.Both the field default and the
from_dictfallback change, because the HTTP daemon rebuildsMaintenanceConfigfrom a dict on every reload and would otherwise pick the old tuple straight back up.A behaviour change worth flagging
On a deployment that has been running on the defaults, the next scheduled pass will start maturing memories it has been leaving alone — a backlog's worth on the first run, in one go. That is the point of the change rather than a side effect, but it is a visible one-off rather than a quiet improvement.
It does not reach everyone.
from_dictonly falls back to the default when the key is absent, so an installation whoseconfig.tomlalready recordsscheduled_consolidation_strategieskeeps whatever it has, including the old three. Those operators need to add"mature"themselves; this PR cannot do it for them without editing their configuration, which would be the wrong sort of helpful.On ordering
Order is not significant. The engine groups strategies into
STRATEGY_TIERS, a tuple of frozensets, and runs them tier by tier rather than in the order the configuration lists them.maturesits betweenmergeandenrichfor readability, nothing more — worth saying, because the tuple reads like a pipeline and is not one.Test plan
pytest tests/unit/test_scheduled_consolidation_handler.py— 17 passed.unified_config.pyreverted tomainand the tests kept, 3 fail:test_defaults,test_from_dict_defaults(both already pinned the tuple and are updated here) and the newtest_defaults_include_mature, which asserts through the field default and thefrom_dictfallback separately.pytest tests/ -m "not stress" -n 4— 7284 passed, 48 skipped, 1 xfailed, which ismain's 7283 plus the one test added here. Two tests intests/unit/test_dashboard_brains_scope.pyfail on this branch and onmainalike: they want a live database and collide with one another under-n. Both pass when that file is run on its own.ruff check src/ tests/clean;ruff format --check src/ tests/reports 739 files already formatted.mypy src/ --ignore-missing-imports— success, no issues found in 354 source files.main.CHANGELOG.mduntouched — left to the release entry, as with fix(storage): bind datetimes in time comparisons so they select by value #191–fix(memory): refresh content-derived fields on compress, restore, and refine #193.Verified by
@RobertSigmundsson