Conversation
…MemoryStrategy (#1036, #208) ## #1036 -- Memory Evolution Research Add three ADR entries (D25-D27) and supporting design docs. **D25 -- GraphRAG Evaluation**: Defer GraphRAG, stay on Mem0 + Qdrant. Benchmarks show +15-25% multi-hop reasoning at 2-3x infra cost and 200-400ms vs 50-150ms query latency. Current episodic/semantic use cases do not require entity traversal. Incremental upgrade path documented. **D26 -- Multi-Agent Memory Consistency**: Adopt append-only writes + MVCC-style snapshot reads for SharedKnowledgeStore. CRDT rejected (space overhead, tombstone resurrection). Event sourcing rejected (compaction complexity). Append-only + MVCC provides audit trail and rollback. **D27 -- RL Consolidation Feasibility**: RL not recommended for MVP. Reward function is unsolved, ground truth requires ~1000 labeled sessions, and training infra cost exceeds token savings by ~12 months at current scale. New docs: docs/design/memory-consistency.md, docs/reference/rl-consolidation-feasibility.md Updated: docs/design/memory.md (Strategy 3 status, GraphRAG migration path) ## #208 -- SelfEditingMemoryStrategy (Strategy 3) Implement the self-editing memory injection strategy. Agents maintain structured core/archival/recall memory tiers and read/write them via tools during execution. **Three tiers:** - Core: SEMANTIC + core tag, injected as SYSTEM message on every turn - Archival: non-WORKING categories, tool-searched via archival_memory_search - Recall: EPISODIC, ID-based lookup via recall_memory_read **New classes:** - SelfEditingMemoryConfig: frozen Pydantic config (token budgets, tag names, safety flags including allow_core_writes) - SelfEditingMemoryStrategy: implements MemoryInjectionStrategy protocol; prepare_messages injects core block; 6 handle_tool_call handlers **6 new tool wrappers** in tools.py: CoreMemoryReadTool, CoreMemoryWriteTool, ArchivalMemorySearchTool, ArchivalMemoryWriteTool, RecallMemoryReadTool, RecallMemoryWriteTool + create_self_editing_tools factory. **Event constants** (9): MEMORY_SELF_EDIT_TOOL_EXECUTE, CORE_READ/WRITE, CORE_WRITE_REJECTED, ARCHIVAL_SEARCH/WRITE, RECALL_READ/WRITE, WRITE_FAILED. **Validator updates** in retrieval_config.py: SELF_EDITING added to supported strategies; diversity_penalty and query_reformulation validators already reject SELF_EDITING via existing conditions. **53 new tests** across 14 test classes covering config validation, strategy init, prepare_messages, tool definitions, all 6 tool handlers, and registry_with_memory_tools augmentation. Full suite: 1551 passed. Closes #1036 Closes #208
The test_client fixture in tests/unit/api/conftest.py creates a full Litestar application (create_app) for every test. Under the full test suite (15k+ tests, 8 xdist workers), these heavyweight app objects accumulate faster than Python's cyclic GC can collect them. At ~98% of the full suite run, combined memory pressure causes worker crashes (process crash, not Python exception) when six specific api/controllers tests trigger Litestar's Pydantic v1 compat layer: - test_update_department_matching_etag - test_get_after_activate - test_create_team_blank_name_rejected - test_trends_success_rate - test_list_projects_after_create - test_returns_blueprint_info_fields All six pass when run in isolation or as the api/controllers batch (824 tests), confirming the crash is OOM-driven, not a logic bug. Fix: add gc.collect() after the with TestClient(app) as client: block exits. This forces immediate collection of the app, its services, and any asyncio tasks retained by reference cycles, preventing the accumulation that triggers the crash. Also fix mypy error in test_self_editing.py: ChatMessage.content is str | None so the 'in' operator requires a non-None guard first.
- security: sanitize handle_tool_call error to avoid leaking backend details - security: add _MAX_CONTENT_LEN (50k) and _MAX_MEMORY_ID_LEN (256) guards to all write handlers and recall_memory_read - types: change handler agent_id params from str to NotBlankStr (CLAUDE.md convention for identifier fields) - config: add _archival_categories_not_empty validator to SelfEditingMemoryConfig - refactor: extract _core_query() helper shared by prepare_messages, core read, and core write handlers (also reduces _handle_core_memory_write below 50 lines) - refactor: introduce _format_error_oversized() to DRY oversized-content errors - refactor: simplify handle_tool_call() -- return directly in try block - fix: change cat_raw error message to generic "Unknown memory category." - docs: add Me3 advisory race-window note to _handle_core_memory_write docstring - docs: index memory-consistency.md in DESIGN_SPEC.md - docs: add SharedKnowledgeStore cross-reference in memory.md - docs: add MEMORY_SELF_EDIT_* event constants to CLAUDE.md logging section - tests: add TestHandleToolCallDispatch -- dispatch, MemoryError/RecursionError re-raise, generic exception wrapping - tests: add registry exception fallback tests (SelfEditing + ToolBased paths) - tests: add TestExtractStr -- parametrized non-string type coverage - tests: add content-length and memory_id-length limit tests to write/read tools - tests: add test_empty_archival_categories_rejected
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🧰 Additional context used📓 Path-based instructions (2)**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
tests/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
⚙️ CodeRabbit configuration file
Files:
🧠 Learnings (2)📓 Common learnings📚 Learning: 2026-03-19T07:12:14.508ZApplied to files:
🔇 Additional comments (8)
WalkthroughThis pull request implements self-editing memory injection strategy for agents, adds comprehensive architectural research documentation, and extends the memory system with multi-agent consistency support. The implementation includes a new 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Tools execution failed with the following error: Failed to run tools: Stream setup permanently failed: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error) Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
There was a problem hiding this comment.
Code Review
This pull request introduces the SelfEditingMemoryStrategy, which enables agents to manage core, archival, and recall memory tiers through a set of six dedicated tools. It also establishes a multi-agent memory consistency model for shared knowledge based on append-only writes and MVCC snapshot reads, accompanied by comprehensive architectural documentation and feasibility analyses for future memory evolutions. The review feedback identifies critical Python 3 syntax errors in exception handling across several files and suggests improving the maintainability of error messages by dynamically generating valid category lists from enums and configurations.
| estimator=self._token_estimator, | ||
| token_budget=token_budget, | ||
| ) | ||
| except builtins.MemoryError, RecursionError: |
| ) | ||
| try: | ||
| return await self._dispatch_tool_call(tool_name, arguments, agent_id) | ||
| except builtins.MemoryError, RecursionError: |
| limit_raw = arguments.get("limit", self._config.archival_search_limit) | ||
| try: | ||
| limit = int(limit_raw) | ||
| except TypeError, ValueError: |
| if isinstance(strategy, SelfEditingMemoryStrategy): | ||
| try: | ||
| augmented = _build_self_editing_registry(tool_registry, strategy, agent_id) | ||
| except MemoryError, RecursionError: |
src/synthorg/memory/self_editing.py
Outdated
| return ( | ||
| f"{ERROR_PREFIX} Unknown memory category. " | ||
| "Valid values: episodic, semantic, procedural, social." | ||
| ) |
There was a problem hiding this comment.
The error message for an unknown category hardcodes the list of valid values. This could become out of sync if the MemoryCategory enum changes. It would be more maintainable to generate this list dynamically.
valid_values = ", ".join(sorted(c.value for c in MemoryCategory if c != MemoryCategory.WORKING))
return (
f"{ERROR_PREFIX} Unknown memory category. "
f"Valid values: {valid_values}."
)| if category not in self._config.archival_categories: | ||
| return ( | ||
| f"{ERROR_PREFIX} Category {category.value!r} cannot be " | ||
| "written to archival memory. " | ||
| "Valid values: episodic, semantic, procedural, social." | ||
| ) |
There was a problem hiding this comment.
The error message for an invalid category hardcodes the list of valid values. This could become out of sync with the archival_categories configuration. It would be more maintainable to generate this list dynamically from the configuration.
if category not in self._config.archival_categories:
valid_values = ", ".join(sorted(c.value for c in self._config.archival_categories))
return (
f"{ERROR_PREFIX} Category {category.value!r} cannot be "
"written to archival memory. "
f"Valid values: {valid_values}."
)There was a problem hiding this comment.
Pull request overview
Implements the self-editing memory injection strategy (Strategy 3) with dedicated core/archival/recall read/write tools, and adds documentation for GraphRAG/consistency research and rollout decisions.
Changes:
- Added
SelfEditingMemoryStrategy+SelfEditingMemoryConfigwith six self-editing tools and size/exception guardrails. - Integrated self-editing tools into
ToolRegistryaugmentation alongside existing tool-based memory strategy. - Added observability event constants, extensive unit tests, and new/updated design & decision documentation (memory consistency, GraphRAG migration path, RL feasibility).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/synthorg/memory/self_editing.py |
New self-editing memory strategy, tool schemas, handlers, limits, logging. |
src/synthorg/memory/tools.py |
Adds six BaseTool wrappers + registry augmentation for self-editing strategy. |
src/synthorg/observability/events/memory.py |
Adds self-editing memory event constants. |
src/synthorg/memory/retrieval_config.py |
Allows SELF_EDITING as a supported injection strategy. |
src/synthorg/memory/__init__.py |
Exposes self-editing config/strategy in package exports. |
tests/unit/memory/test_self_editing.py |
New unit test suite covering config, tools, dispatch, limits, and registry behavior. |
tests/unit/memory/test_retrieval_config.py |
Updates strategy validation test to accept SELF_EDITING. |
tests/unit/memory/test_init.py |
Updates __all__ expectations to include self-editing exports. |
tests/unit/api/conftest.py |
Adds post-fixture gc.collect() to reduce OOM risk in large test runs. |
docs/design/memory.md |
Updates self-editing strategy section and links to consistency doc + GraphRAG migration tip. |
docs/design/memory-consistency.md |
New consistency model doc (append-only + MVCC snapshot reads). |
docs/DESIGN_SPEC.md |
Indexes the new memory consistency design page. |
docs/architecture/decisions.md |
Adds decisions D25–D27 on memory evolution/consistency/RL consolidation. |
docs/reference/rl-consolidation-feasibility.md |
New feasibility analysis reference page. |
CLAUDE.md |
Adds self-editing memory event constants to the logging events list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| categories: frozenset[MemoryCategory] | None = None | ||
| cat_raw = arguments.get("category") | ||
| if cat_raw is not None: | ||
| try: | ||
| categories = frozenset({MemoryCategory(str(cat_raw))}) | ||
| except ValueError: | ||
| return ( | ||
| f"{ERROR_PREFIX} Unknown memory category. " | ||
| "Valid values: episodic, semantic, procedural, social." | ||
| ) | ||
|
|
||
| limit_raw = arguments.get("limit", self._config.archival_search_limit) | ||
| try: | ||
| limit = int(limit_raw) | ||
| except TypeError, ValueError: | ||
| limit = self._config.archival_search_limit | ||
| limit = max(1, min(limit, self._config.archival_search_limit)) |
There was a problem hiding this comment.
archival_memory_search currently allows querying any MemoryCategory (including WORKING) and, when no category is provided, it passes categories=None which typically searches across all categories. That breaks the tier contract (“archival = non-WORKING only”) and can leak WORKING/session-scoped memories through the archival tool. Consider defaulting categories to self._config.archival_categories when omitted, and rejecting/ignoring category filters not in self._config.archival_categories (especially WORKING).
| found=entry is not None, | ||
| ) | ||
| if entry is None: | ||
| return f"{ERROR_PREFIX} Memory not found: {memory_id!r}" |
There was a problem hiding this comment.
recall_memory_read retrieves an entry by ID but does not enforce that the fetched entry is EPISODIC. As written, an agent can use IDs surfaced by other tools (e.g., core_memory_read outputs id=...) to fetch non-episodic entries via recall_memory_read, undermining the intended tier separation. Consider validating entry.category == MemoryCategory.EPISODIC and returning an error otherwise.
| return f"{ERROR_PREFIX} Memory not found: {memory_id!r}" | |
| return f"{ERROR_PREFIX} Memory not found: {memory_id!r}" | |
| if entry.category != MemoryCategory.EPISODIC: | |
| return ( | |
| f"{ERROR_PREFIX} Memory {memory_id!r} is not an episodic memory " | |
| "and cannot be read via recall_memory_read." | |
| ) |
src/synthorg/memory/self_editing.py
Outdated
| try: | ||
| category = MemoryCategory(str(cat_raw)) | ||
| except ValueError: | ||
| return ( | ||
| f"{ERROR_PREFIX} Unknown memory category. " | ||
| "Valid values: episodic, semantic, procedural, social." | ||
| ) | ||
|
|
||
| if category not in self._config.archival_categories: | ||
| return ( | ||
| f"{ERROR_PREFIX} Category {category.value!r} cannot be " | ||
| "written to archival memory. " | ||
| "Valid values: episodic, semantic, procedural, social." |
There was a problem hiding this comment.
When category is not permitted by self._config.archival_categories, the error text always lists episodic, semantic, procedural, social as “Valid values”. Since archival_categories is configurable (and may exclude some of these), this message can be inaccurate. Consider rendering the allowed set from self._config.archival_categories (and ensuring WORKING is never included).
| try: | |
| category = MemoryCategory(str(cat_raw)) | |
| except ValueError: | |
| return ( | |
| f"{ERROR_PREFIX} Unknown memory category. " | |
| "Valid values: episodic, semantic, procedural, social." | |
| ) | |
| if category not in self._config.archival_categories: | |
| return ( | |
| f"{ERROR_PREFIX} Category {category.value!r} cannot be " | |
| "written to archival memory. " | |
| "Valid values: episodic, semantic, procedural, social." | |
| valid_archival_categories = ", ".join( | |
| sorted( | |
| category.value | |
| for category in self._config.archival_categories | |
| if category is not MemoryCategory.WORKING | |
| ) | |
| ) | |
| try: | |
| category = MemoryCategory(str(cat_raw)) | |
| except ValueError: | |
| return ( | |
| f"{ERROR_PREFIX} Unknown memory category. " | |
| f"Valid values: {valid_archival_categories}." | |
| ) | |
| if category not in self._config.archival_categories: | |
| return ( | |
| f"{ERROR_PREFIX} Category {category.value!r} cannot be " | |
| "written to archival memory. " | |
| f"Valid values: {valid_archival_categories}." |
| except Exception as exc: | ||
| logger.warning( | ||
| MEMORY_SELF_EDIT_WRITE_FAILED, | ||
| tool_name=tool_name, | ||
| agent_id=agent_id, | ||
| error=str(exc), | ||
| exc_info=True, | ||
| ) | ||
| return f"{ERROR_PREFIX} Memory operation failed." |
There was a problem hiding this comment.
handle_tool_call logs MEMORY_SELF_EDIT_WRITE_FAILED for any tool exception (including core/archival/recall reads and archival search). This will misclassify failures in telemetry/dashboards. Consider using a tool-generic failure event (or introducing separate *_READ_FAILED / *_SEARCH_FAILED events) and reserving WRITE_FAILED for write operations only.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1129 +/- ##
==========================================
+ Coverage 89.03% 89.07% +0.03%
==========================================
Files 824 825 +1
Lines 47903 48164 +261
Branches 4821 4845 +24
==========================================
+ Hits 42651 42902 +251
- Misses 4352 4359 +7
- Partials 900 903 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…bbit - Dynamic valid values in archival search/write error messages (Gemini) - Add debug logging for invalid limit input fallback (silent-failure) - Update InjectionStrategy.SELF_EDITING docstring from "future" to "implemented" - Update README.md memory section to mention self-editing strategy - Split test_self_editing.py (945 lines) into two files under 800-line limit - Add parametrized tests for non-integer limit values - Add parametrized tests for non-string memory_id values
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/unit/memory/test_self_editing_tools.py`:
- Around line 139-145: Rename the misleading test function
test_is_not_error_on_success to a name that reflects its assertion (for example
test_category_is_memory or test_tool_uses_memory_category) so it matches the
docstring and the assertion that CoreMemoryReadTool(strategy=_make_strategy(),
agent_id="agent-1").category == ToolCategory.MEMORY; update the test function
name accordingly while leaving the body (use of _make_strategy,
CoreMemoryReadTool, and ToolCategory.MEMORY) unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: d692d50f-a1b6-4ee5-a9bd-d4f2930c6c89
📒 Files selected for processing (5)
README.mdsrc/synthorg/memory/injection.pysrc/synthorg/memory/self_editing.pytests/unit/memory/test_self_editing.pytests/unit/memory/test_self_editing_tools.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Python 3.14+ with PEP 649 native lazy annotations; no
from __future__ import annotationsUse PEP 758 except syntax:
except A, B:(no parentheses) - ruff enforces on Python 3.14All public functions must have type hints; mypy strict mode required
Google style docstrings required on public classes and functions, enforced by ruff D rules
Create new objects instead of mutating existing ones; use
copy.deepcopy()for non-Pydantic internal collections andMappingProxyTypewrapping for read-only enforcementUse frozen Pydantic models for config/identity; separate mutable-via-copy models using
model_copy(update=...)for runtime state. Never mix static config fields with mutable runtime fieldsUse Pydantic v2 with
BaseModel,model_validator,computed_field,ConfigDict. Always useallow_inf_nan=Falsein allConfigDictdeclarationsUse
@computed_fieldfor derived values instead of storing redundant fields. For numeric fields, useallow_inf_nan=Falseto rejectNaN/Infat validation timeUse
NotBlankStrfromcore.typesfor all identifier/name fields (including optional and tuple variants) instead of manual whitespace validatorsPrefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code; prefer structured concurrency over barecreate_taskLine length: 88 characters (ruff)
Functions must be < 50 lines, files < 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)
Files:
src/synthorg/memory/injection.pytests/unit/memory/test_self_editing.pysrc/synthorg/memory/self_editing.pytests/unit/memory/test_self_editing_tools.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic must import
from synthorg.observability import get_loggerand createlogger = get_logger(__name__)Always use
loggeras variable name, not_loggerorlogUse event name constants from domain-specific modules under
synthorg.observability.events(e.g.,API_REQUEST_STARTEDfromevents.api). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANTAlways use structured kwargs for logging:
logger.info(EVENT, key=value)- never uselogger.info('msg %s', val)All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation and internal flow
Pure data models, enums, and re-exports do NOT need logging
All provider calls go through
BaseCompletionProviderwhich applies retry + rate limiting automatically; never implement retry logic in driver subclasses or calling codeRetryConfig and RateLimiterConfig are set per-provider in
ProviderConfig; retryable errors haveis_retryable=TrueMaintain 80% minimum test coverage (enforced in CI)
Use vendor-agnostic names in project-owned code:
example-provider,example-large-001,example-medium-001,example-small-001,large/medium/smallaliases. Never use real vendor names (Anthropic, OpenAI, Claude, GPT). Tests must usetest-provider,test-small-001. Vendor names only allowed in: Design ops page,.claude/files, third-party imports, provider presets
Files:
src/synthorg/memory/injection.pysrc/synthorg/memory/self_editing.py
⚙️ CodeRabbit configuration file
This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.
Files:
src/synthorg/memory/injection.pysrc/synthorg/memory/self_editing.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Never use
import logging,logging.getLogger(), orprint()in application code; exceptions allowed only in observability module setup files
Files:
src/synthorg/memory/injection.pysrc/synthorg/memory/self_editing.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mark tests with
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slowUse
asyncio_mode = 'auto'for pytest - no manual@pytest.mark.asyncioneededGlobal test timeout: 30 seconds per test (in
pyproject.toml); non-default overrides liketimeout(60)are allowed but do not add globalpytest.mark.timeout(30)markersPrefer
@pytest.mark.parametrizefor testing similar casesUse Hypothesis for property-based testing with
@given+@settings. Configure profiles intests/conftest.py:ci(10 examples, deterministic),dev(1000 examples),fuzz(10,000 examples, no deadline)Never skip, dismiss, or ignore flaky tests - fix them fully and fundamentally. Mock
time.monotonic()andasyncio.sleep()for timing-sensitive tests; useasyncio.Event().wait()for indefinite blocking
Files:
tests/unit/memory/test_self_editing.pytests/unit/memory/test_self_editing_tools.py
⚙️ CodeRabbit configuration file
Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare
@settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which@given() honors automatically.
Files:
tests/unit/memory/test_self_editing.pytests/unit/memory/test_self_editing_tools.py
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/memory/**/*.py : Memory package (memory/): pluggable MemoryBackend protocol, backends/ (Mem0 adapter), retrieval pipeline (ranking, RRF fusion, injection, formatting, non-inferable filtering), shared org memory (org/), consolidation/archival (density-aware: DensityClassifier, AbstractiveSummarizer, ExtractivePreserver, DualModeConsolidationStrategy)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Read the relevant `docs/design/` page before implementing any feature or planning any issue. Design spec is the starting point for architecture, data models, and behavior
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Alert the user and explain why if implementation deviates from the spec; do NOT silently diverge - every deviation needs explicit user approval
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Update relevant `docs/design/` page to reflect the reality when approved deviations occur
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Be critical at every phase of planning and implementation, actively look for ways to improve the design. Surface improvements as suggestions, not silent changes - user decides
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Prioritize issues by dependency order, not priority labels - unblocked dependencies come first
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: ALWAYS include `-n 8` when running pytest locally - never run tests sequentially. CI uses `-n auto`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: When Hypothesis finds a failure, fix the underlying bug and add an explicit `example(...)` decorator to permanently cover the case in CI
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Git commits follow `<type>: <description>` format with types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Signed commits required on `main` via branch protection - all commits must be GPG/SSH signed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Use branch naming `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Pre-commit hooks enforce: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint, golangci-lint, go vet, no-em-dashes, no-redundant-timeout, eslint-web
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Pre-push hooks: mypy type-check (affected modules only), pytest unit tests (affected modules only), golangci-lint, go vet, go test (CLI), eslint-web. Foundational module changes or conftest changes trigger full runs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Never use `cd` in Bash commands - use absolute paths or run commands directly. Exception: `bash -c "cd <dir> && <cmd>"` is safe for tools without a `-C` flag
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Never use Bash to write or modify files - use the Write or Edit tools. Do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, or `tee` for file creation/modification
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Use `go -C cli` (never `cd cli`) for Go CLI commands
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Enforce web design system rules via PostToolUse hook (`scripts/check_web_design_system.py`) on every Edit/Write to `web/src/`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Use Bash for `gh issue list` queries; do not use MCP `list_issues` tool due to unreliable field data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Use squash merge strategy - PR body becomes squash commit message on main. Preserve `Closes `#NNN`` references in PR body
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: After finishing an issue implementation, create a feature branch, commit, and push immediately - do NOT create a PR automatically or leave work uncommitted on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: NEVER create a PR directly with `gh pr create` (blocked by hookify) - ALWAYS use `/pre-pr-review` to create PRs. For trivial changes: `/pre-pr-review quick` skips agents but runs automated checks
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: After PR exists, use `/aurelio-review-pr` to handle external reviewer feedback
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-07T20:29:21.051Z
Learning: Fix everything valid found by review agents - never skip. No deferring, no 'out of scope' skipping
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/memory/**/*.py : Memory package (memory/): pluggable MemoryBackend protocol, backends/ (Mem0 adapter), retrieval pipeline (ranking, RRF fusion, injection, formatting, non-inferable filtering), shared org memory (org/), consolidation/archival (density-aware: DensityClassifier, AbstractiveSummarizer, ExtractivePreserver, DualModeConsolidationStrategy)
Applied to files:
README.mdtests/unit/memory/test_self_editing.pysrc/synthorg/memory/self_editing.pytests/unit/memory/test_self_editing_tools.py
📚 Learning: 2026-04-06T16:35:12.934Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T16:35:12.934Z
Learning: Applies to **/memory/MEMORY.md : The MEMORY.md index file should contain one-line pointers to other memory files
Applied to files:
README.md
📚 Learning: 2026-04-06T16:35:12.934Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T16:35:12.934Z
Learning: Applies to **/memory/**/*.md : Memory directory files use markdown with YAML frontmatter containing name, description, and type fields
Applied to files:
README.md
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.
Applied to files:
README.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).
Applied to files:
README.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Applied to files:
README.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)
Applied to files:
README.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
README.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Applied to files:
README.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)
Applied to files:
README.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)
Applied to files:
README.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
Applied to files:
README.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/memory/**/*.py : Use MemoryBackend protocol with pluggable backends (Mem0 adapter available at backends/mem0/) for persistent agent memory
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-31T21:07:37.470Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T21:07:37.470Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) per PEP 758 exception syntax on Python 3.14
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-04-07T16:48:04.262Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T16:48:04.262Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) instead of `except (A, B):` for multiple exceptions—PEP 758 except syntax enforced by ruff on Python 3.14.
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to **/*.py : Use `except A, B:` syntax (without parentheses) per PEP 758 for exception handling in Python 3.14
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to **/*.py : Use `except A, B:` syntax (no parentheses) for exception handling — PEP 758 exception syntax enforced by ruff on Python 3.14
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to **/*.py : Handle errors explicitly; never silently swallow exceptions
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to **/*.py : Handle errors explicitly, never silently swallow exceptions
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to **/*.py : Use PEP 758 except syntax with `except A, B:` (no parentheses) for multiple exceptions—ruff enforces this on Python 3.14.
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to **/*.py : Handle errors explicitly—never silently swallow exceptions.
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to **/*.py : Use PEP 758 except syntax: `except A, B:` (no parentheses) — enforced by ruff on Python 3.14
Applied to files:
src/synthorg/memory/self_editing.py
📚 Learning: 2026-03-15T16:55:07.730Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:55:07.730Z
Learning: Applies to **/*.py : Use PEP 758 except syntax: use `except A, B:` (no parentheses) — ruff enforces this on Python 3.14.
Applied to files:
src/synthorg/memory/self_editing.py
🔇 Additional comments (29)
src/synthorg/memory/injection.py (1)
31-31: LGTM!Docstring accurately updated to reflect that
SELF_EDITINGis now implemented, consistent with the newSelfEditingMemoryStrategyin this PR.README.md (1)
82-82: LGTM!README accurately updated to document all three memory injection strategies now available.
tests/unit/memory/test_self_editing.py (7)
31-76: LGTM!Well-designed test helpers with sensible defaults. Using
spec=MemoryBackendon the mock ensures type safety.
83-156: LGTM!Comprehensive config validation tests covering defaults, bounds, WORKING rejection, immutability, and empty set rejection.
163-178: LGTM!Constructor constraint tests properly verify backend requirement and strategy name.
185-263: LGTM!Thorough coverage of
prepare_messagesbehavior including core entry formatting, token budget respect, empty returns, query construction verification, and error handling.
270-296: LGTM!Tool definition tests verify count, names, and schema presence.
303-354: LGTM!Excellent dispatch tests covering unknown tools, system error propagation, and critically verifying that backend error details are not leaked to the LLM.
361-386: LGTM!Comprehensive
_extract_strtests covering all edge cases including non-string types, blanks, missing keys, and whitespace stripping.tests/unit/memory/test_self_editing_tools.py (8)
45-107: LGTM!Well-designed helpers including
_DummyToolfor registry augmentation testing.
152-217: LGTM!Comprehensive
CoreMemoryWriteTooltests covering successful writes,allow_core_writesguard, max entries limit, content validation, and oversized content rejection.
224-302: LGTM!Thorough
ArchivalMemorySearchTooltests covering query search, category filtering, limit clamping, validation errors, and non-integer limit fallback.
309-385: LGTM!Comprehensive
ArchivalMemoryWriteTooltests covering auto-tagging, WORKING rejection, content validation, and memory ID return.
392-457: LGTM!Thorough
RecallMemoryReadTooltests covering successful retrieval, not-found handling, blank/oversized/non-stringmemory_idvalidation.
464-520: LGTM!Comprehensive
RecallMemoryWriteTooltests verifying EPISODIC category enforcement, ID return, auto-tagging, and content validation.
527-618: LGTM!Excellent registry integration tests covering six-tool augmentation, existing tool preservation, None handling, ToolBasedInjectionStrategy regression, and exception fallback behavior.
625-668: LGTM!Thorough
create_self_editing_toolstests verifying tool count, types, categories, names, and critically thatagent_idis properly bound and passed to backend calls.src/synthorg/memory/self_editing.py (12)
59-76: LGTM!Well-documented tool name constants and sensible input size limits for LLM-supplied values.
77-171: LGTM!Well-defined JSON schemas with appropriate constraints. Using
MappingProxyTypeensures immutability at module level.
172-222: LGTM!Clean helper functions with clear responsibilities.
229-325: LGTM!Well-designed frozen config with
allow_inf_nan=False, appropriate field constraints, and validators that enforce WORKING exclusion and non-empty archival categories.
332-389: LGTM!Well-implemented strategy initialization with
__slots__for memory efficiency, proper backend validation, and correct_core_query()usingtext=Nonefor metadata-only filtering.
390-443: LGTM!Well-implemented
prepare_messageswith correct core memory fetching, token budget enforcement viaformat_memory_context, and appropriate error handling that fails open (returns()) on backend errors while propagating system errors.
444-502: LGTM!Well-documented tool definitions with clear descriptions. Using
copy.deepcopy(dict(...))ensures schema independence.
503-570: LGTM!Clean dispatch implementation with proper error handling. Security-conscious: returns generic "Memory operation failed." message without exposing backend error details.
575-639: LGTM!Well-implemented core memory handlers with proper guardrails (
allow_core_writes,core_max_entries). Good documentation noting the non-atomic capacity check is advisory.
640-691: LGTM!Well-implemented archival search with proper query validation, category parsing, and limit clamping. Good defensive logging that truncates raw limit to prevent log injection.
692-738: LGTM!Well-implemented archival write with comprehensive validation: content size limits, category validation against configured
archival_categories, and conditional auto-tagging.
739-786: LGTM!Well-implemented recall handlers with consistent validation patterns.
_handle_recall_memory_writecorrectly forcesMemoryCategory.EPISODICas documented.
…isleading test - Remove gc.collect() from test_client fixture teardown in api/conftest.py (added ~5s to each of ~250 API tests, inflating CI from ~5min to ~15min) - Rename test_is_not_error_on_success to test_tool_uses_memory_category to match the actual assertion (tool.category == ToolCategory.MEMORY)
🤖 I have created a release *beep* *boop* --- ## [0.6.4](v0.6.3...v0.6.4) (2026-04-07) ### Features * analytics and metrics runtime pipeline ([#226](#226), [#225](#225), [#227](#227), [#224](#224)) ([#1127](#1127)) ([ec57641](ec57641)) * engine intelligence -- quality signals, health monitoring, trajectory scoring, coordination metrics ([#1099](#1099)) ([aac2029](aac2029)), closes [#697](#697) [#707](#707) [#705](#705) [#703](#703) * enterprise-grade auth -- HttpOnly cookie sessions, CSRF, lockout, session limits ([#1102](#1102)) ([d3022c7](d3022c7)), closes [#1068](#1068) * implement core tool categories and granular sub-constraints ([#1101](#1101)) ([0611b53](0611b53)), closes [#1034](#1034) [#220](#220) * memory evolution -- GraphRAG/consistency research + SelfEditingMemoryStrategy ([#1036](#1036), [#208](#208)) ([#1129](#1129)) ([a9acda3](a9acda3)) * security hardening -- sandbox, risk override, SSRF self-heal, DAST fix ([#1100](#1100)) ([31e7273](31e7273)), closes [#1098](#1098) [#696](#696) [#222](#222) [#671](#671) ### Bug Fixes * harden agent identity versioning post-review ([#1128](#1128)) ([8eb2859](8eb2859)), closes [#1076](#1076) ### Documentation * engine architecture research ([#688](#688) [#690](#690) [#848](#848) [#687](#687)) ([#1114](#1114)) ([59b31f9](59b31f9)) ### Maintenance * add .claudeignore and split CLAUDE.md for token optimization ([#1112](#1112)) ([b0fbd18](b0fbd18)) * bump github.com/sigstore/protobuf-specs from 0.5.0 to 0.5.1 in /cli in the all group ([#1106](#1106)) ([73089c9](73089c9)) * bump jsdom from 29.0.1 to 29.0.2 in /site in the all group ([#1107](#1107)) ([8e99dce](8e99dce)) * bump jsdom from 29.0.1 to 29.0.2 in /web in the all group ([#1108](#1108)) ([ce8c749](ce8c749)) * bump python from `fb83750` to `6869258` in /docker/backend in the all group ([#1104](#1104)) ([4911726](4911726)) * bump python from `fb83750` to `6869258` in /docker/web in the all group ([#1103](#1103)) ([87bdf09](87bdf09)) * bump the all group across 1 directory with 4 updates ([#1111](#1111)) ([f702464](f702464)) * bump the all group in /docker/sandbox with 2 updates ([#1105](#1105)) ([05a91ca](05a91ca)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
Implements Strategy 3 (self-editing memory) from design spec §7.7 and lands the GraphRAG/consistency research from #1036.
#208 -- SelfEditingMemoryStrategy
Agents now maintain structured core/archival/recall memory blocks and read/write them via six dedicated tools during execution.
Three memory tiers:
coretag): Always injected as a SYSTEM message. Agents read/write viacore_memory_read/core_memory_write.archival_memory_search/archival_memory_write.recall_memory_read/recall_memory_write.New files:
src/synthorg/memory/self_editing.py--SelfEditingMemoryStrategy,SelfEditingMemoryConfig, six tool name constants,_extract_str/_format_entries/_format_error_oversizedhelperssrc/synthorg/memory/tools.py-- sixBaseToolwrappers,create_self_editing_tools(),registry_with_memory_tools()updated to handle both ToolBased and SelfEditing strategiessrc/synthorg/observability/events/memory.py-- nine newMEMORY_SELF_EDIT_*event constantstests/unit/memory/test_self_editing.py-- 75 unit tests covering config validation, all six tools, dispatch error handling, registry fallback,_extract_strtype safety, content/ID length limitsSecurity hardening:
handle_tool_callcatches genericExceptionand returns a generic"Error: Memory operation failed."-- raw backend error details (e.g. SQLite messages) are never exposed to the LLM_MAX_CONTENT_LEN = 50_000and_MAX_MEMORY_ID_LEN = 256guards on all write handlers andrecall_memory_readprevent unbounded writes from LLM-supplied valuescat_rawnever echoed into error messages (fixed to generic "Unknown memory category.")Config guardrails:
archival_categoriesvalidator rejectsWORKING(session-scoped, must not be persisted)archival_categoriesmust be non-empty (empty set would silently block all archival writes)allow_core_writes=Falselocks core memory to read-only for that agentcore_max_entriescap prevents unbounded core memory growth#1036 -- GraphRAG / Consistency Research
docs/design/memory-consistency.md-- new design page: append-only writes, MVCC snapshot reads, conflict handling, deployment rolloutdocs/design/memory.md-- SharedKnowledgeStore cross-reference to memory-consistency.mdDocumentation updates
docs/DESIGN_SPEC.md-- indexedmemory-consistency.mdin the design pages tableCLAUDE.md-- added all nineMEMORY_SELF_EDIT_*constants to the logging events listCloses #208
Closes #1036