feat: implement SharedKnowledgeStore append-only + MVCC consistency model (Phase 1.5)#1134
feat: implement SharedKnowledgeStore append-only + MVCC consistency model (Phase 1.5)#1134
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements Multi-Version Concurrency Control (MVCC) for the organizational memory system, transitioning the SQLite backend to an append-only operation log with a materialized snapshot. The changes introduce new models for operation logging, support for metadata tags, and functionality for point-in-time snapshots and audit trails. Feedback identifies critical improvements for the audit trail, specifically requiring the delete method to record the actual retracting author rather than the original author. Additionally, the snapshot logic needs adjustment to preserve the initial created_at timestamp during updates, and the operation log schema should be expanded to include all author metadata fields for complete historical reconstruction.
src/synthorg/memory/org/store.py
Outdated
| @@ -136,21 +194,68 @@ async def list_by_category( | |||
| ... | |||
|
|
|||
| async def delete(self, fact_id: NotBlankStr) -> bool: | |||
There was a problem hiding this comment.
The delete method should accept an author: OrgFactAuthor argument. Currently, the implementation reuses the author of the existing fact for the RETRACT operation log entry. This is incorrect for an audit trail, as it should record the identity of the agent or human who performed the retraction, not the original author of the fact.
| async def delete(self, fact_id: NotBlankStr) -> bool: | |
| async def delete(self, fact_id: NotBlankStr, author: OrgFactAuthor) -> bool: |
src/synthorg/memory/org/store.py
Outdated
| "INSERT OR REPLACE INTO org_facts_snapshot " | ||
| "(fact_id, content, category, tags, " | ||
| "author_agent_id, author_seniority, author_is_human, " | ||
| "author_autonomy_level, created_at, retracted_at, " | ||
| "version) " | ||
| "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)", | ||
| ( | ||
| fact.id, | ||
| fact.content, | ||
| fact.category.value, | ||
| _tags_to_json(fact.tags), | ||
| fact.author.agent_id, | ||
| fact.author.seniority.value if fact.author.seniority else None, | ||
| (fact.author.seniority.value if fact.author.seniority else None), | ||
| int(fact.author.is_human), | ||
| ( | ||
| fact.author.autonomy_level.value | ||
| if fact.author.autonomy_level | ||
| else None | ||
| ), | ||
| fact.created_at.isoformat(), | ||
| version, | ||
| ), | ||
| ) |
There was a problem hiding this comment.
The INSERT OR REPLACE statement overwrites the created_at field in the snapshot table with the current fact's timestamp. This violates the definition of created_at as the "Timestamp of first PUBLISH". When re-publishing (updating) a fact, the original creation timestamp should be preserved. Use INSERT INTO ... ON CONFLICT(fact_id) DO UPDATE to maintain the original created_at while updating other fields.
await db.execute(
"INSERT INTO org_facts_snapshot "
"(fact_id, content, category, tags, "
"author_agent_id, author_seniority, author_is_human, "
"author_autonomy_level, created_at, retracted_at, "
"version) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?) "
"ON CONFLICT(fact_id) DO UPDATE SET "
"content=excluded.content, "
"category=excluded.category, "
"tags=excluded.tags, "
"author_agent_id=excluded.author_agent_id, "
"author_seniority=excluded.author_seniority, "
"author_is_human=excluded.author_is_human, "
"author_autonomy_level=excluded.author_autonomy_level, "
"retracted_at=NULL, "
"version=excluded.version",
(
fact.id,
fact.content,
fact.category.value,
_tags_to_json(fact.tags),
fact.author.agent_id,
(fact.author.seniority.value if fact.author.seniority else None),
int(fact.author.is_human),
(
fact.author.autonomy_level.value
if fact.author.autonomy_level
else None
),
fact.created_at.isoformat(),
version,
),
)
src/synthorg/memory/org/store.py
Outdated
| version, now = await self._append_to_operation_log( | ||
| db, | ||
| fact_id=fact_id, | ||
| operation_type="RETRACT", | ||
| content=None, | ||
| tags=(), | ||
| author_agent_id=row["author_agent_id"], | ||
| author_autonomy_level=( | ||
| AutonomyLevel(row["author_autonomy_level"]) | ||
| if row["author_autonomy_level"] | ||
| else None | ||
| ), | ||
| ) |
src/synthorg/memory/org/store.py
Outdated
| CREATE TABLE IF NOT EXISTS org_facts_operation_log ( | ||
| operation_id TEXT PRIMARY KEY, | ||
| fact_id TEXT NOT NULL, | ||
| operation_type TEXT NOT NULL CHECK(operation_type IN ('PUBLISH', 'RETRACT')), | ||
| content TEXT, | ||
| tags TEXT NOT NULL DEFAULT '[]', | ||
| author_agent_id TEXT, | ||
| author_autonomy_level TEXT, | ||
| timestamp TEXT NOT NULL, | ||
| version INTEGER NOT NULL, | ||
| UNIQUE(fact_id, version) | ||
| ) |
There was a problem hiding this comment.
The org_facts_operation_log table is missing author_seniority and author_is_human columns. These fields are part of the OrgFactAuthor model and are necessary to fully reconstruct the author's state from the operation log (e.g., for historical auditing or time-travel queries).
_CREATE_OPERATION_LOG_SQL = """\
CREATE TABLE IF NOT EXISTS org_facts_operation_log (
operation_id TEXT PRIMARY KEY,
fact_id TEXT NOT NULL,
operation_type TEXT NOT NULL CHECK(operation_type IN ('PUBLISH', 'RETRACT')),
content TEXT,
tags TEXT NOT NULL DEFAULT '[]',
author_agent_id TEXT,
author_seniority TEXT,
author_is_human INTEGER NOT NULL DEFAULT 0,
author_autonomy_level TEXT,
timestamp TEXT NOT NULL,
version INTEGER NOT NULL,
UNIQUE(fact_id, version)
)
"""
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.
Pull request overview
Implements Phase 1.5 of the org memory consistency design by switching the SQLite org fact store to an append-only operation log + materialized snapshot (MVCC-style), adding audit/time-travel APIs, and extending org memory models/IO to include tags and author autonomy metadata.
Changes:
- Replaced
org_factstable semantics withorg_facts_operation_log(append-only) +org_facts_snapshot(current state) and updated read/write paths accordingly. - Added MVCC/time-travel surface area (
snapshot_at,get_operation_log), new MVCC Pydantic models, and new observability event constants. - Threaded new metadata through the stack (
OrgFact.tags,OrgFactAuthor.autonomy_level) and expanded unit tests (including MVCC-specific test suite).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/synthorg/memory/org/store.py |
Core MVCC implementation: schema, append-only log writes, snapshot reads, time-travel queries, audit log retrieval. |
src/synthorg/memory/org/models.py |
Adds tags/autonomy fields and introduces OperationLogEntry / OperationLogSnapshot models + validation. |
src/synthorg/memory/org/hybrid_backend.py |
Passes tags from OrgFactWriteRequest into OrgFact persisted via the store. |
src/synthorg/observability/events/org_memory.py |
Adds MVCC-specific structured logging event constants. |
src/synthorg/memory/org/__init__.py |
Re-exports MVCC models in the org memory public API. |
docs/design/memory-consistency.md |
Updates rollout narrative and clarifies MVCC APIs live on OrgFactStore. |
CLAUDE.md |
Updates logging event-constants examples to include org memory MVCC events. |
tests/unit/memory/org/test_store.py |
Updates/extends baseline store tests for MVCC behavior and tags. |
tests/unit/memory/org/test_mvcc_store.py |
New MVCC-focused test suite (schema, versioning, retract semantics, snapshot_at, audit trail). |
tests/unit/memory/org/test_models.py |
Adds tests for new author autonomy, tags, and MVCC model validations. |
tests/unit/memory/org/test_hybrid_backend.py |
Adds coverage that backend writes persist and return tags. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/synthorg/memory/org/store.py
Outdated
| db = self._require_connected() | ||
| try: | ||
| await db.execute("BEGIN IMMEDIATE") | ||
| version, _ = await self._append_to_operation_log( | ||
| db, | ||
| fact_id=fact.id, |
There was a problem hiding this comment.
After BEGIN IMMEDIATE, if any sqlite3.Error occurs during the log append or snapshot upsert, the code raises without an explicit ROLLBACK. That can leave the connection in an open transaction and cause subsequent writes to fail. Add a rollback in the error path (e.g., except/finally) before raising OrgMemoryWriteError.
src/synthorg/memory/org/store.py
Outdated
| db = self._require_connected() | ||
| try: | ||
| await db.execute("BEGIN IMMEDIATE") | ||
| cursor = await db.execute( | ||
| "SELECT fact_id, author_agent_id, author_autonomy_level " | ||
| "FROM org_facts_snapshot " | ||
| "WHERE fact_id = ? AND retracted_at IS NULL", | ||
| (fact_id,), | ||
| ) | ||
| row = await cursor.fetchone() | ||
| if row is None: | ||
| await db.execute("ROLLBACK") | ||
| return False | ||
| version, now = await self._append_to_operation_log( |
There was a problem hiding this comment.
delete() opens BEGIN IMMEDIATE and then can raise on sqlite3.Error without rolling back the transaction. Please ensure a ROLLBACK happens on all error paths after the BEGIN (not only the row is None early return) so the connection doesn’t remain locked/in-transaction.
src/synthorg/memory/org/store.py
Outdated
| cursor = await db.execute( | ||
| "SELECT fact_id, author_agent_id, author_autonomy_level " | ||
| "FROM org_facts_snapshot " | ||
| "WHERE fact_id = ? AND retracted_at IS NULL", | ||
| (fact_id,), | ||
| ) | ||
| row = await cursor.fetchone() | ||
| if row is None: | ||
| await db.execute("ROLLBACK") | ||
| return False | ||
| version, now = await self._append_to_operation_log( | ||
| db, | ||
| fact_id=fact_id, | ||
| operation_type="RETRACT", | ||
| content=None, | ||
| tags=(), | ||
| author_agent_id=row["author_agent_id"], | ||
| author_autonomy_level=( | ||
| AutonomyLevel(row["author_autonomy_level"]) | ||
| if row["author_autonomy_level"] | ||
| else None | ||
| ), |
There was a problem hiding this comment.
The RETRACT log entry is currently populated with author_agent_id/author_autonomy_level read from the snapshot row (i.e., the last publisher), not the actor performing the retraction. Since OperationLogEntry.author_* is documented as “agent that performed the operation”, this will misattribute retract operations in the audit trail. Consider extending delete() to accept an OrgFactAuthor (passed from the caller) or storing NULL/system values for retract until the API can carry the retractor identity.
src/synthorg/memory/org/store.py
Outdated
| OrgMemoryQueryError: If the JSON is not a list. | ||
| """ | ||
| parsed = json.loads(raw) | ||
| if not isinstance(parsed, list): | ||
| msg = f"Tags must be a JSON array, got {type(parsed).__name__}" | ||
| raise OrgMemoryQueryError(msg) |
There was a problem hiding this comment.
_tags_from_json() raises OrgMemoryQueryError when the decoded JSON isn’t a list, but callers like _snapshot_row_to_org_fact() only catch KeyError/ValueError/ValidationError. A malformed-but-valid tags payload (e.g. {}) would bypass the row-parse warning log/wrapping path. Either raise ValueError from _tags_from_json() (and let callers wrap/log), or have callers handle OrgMemoryQueryError as well for consistent error reporting.
| OrgMemoryQueryError: If the JSON is not a list. | |
| """ | |
| parsed = json.loads(raw) | |
| if not isinstance(parsed, list): | |
| msg = f"Tags must be a JSON array, got {type(parsed).__name__}" | |
| raise OrgMemoryQueryError(msg) | |
| ValueError: If the JSON is not a list. | |
| """ | |
| parsed = json.loads(raw) | |
| if not isinstance(parsed, list): | |
| msg = f"Tags must be a JSON array, got {type(parsed).__name__}" | |
| raise ValueError(msg) |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1134 +/- ##
========================================
Coverage 88.98% 88.98%
========================================
Files 851 852 +1
Lines 49633 49733 +100
Branches 4977 4983 +6
========================================
+ Hits 44164 44255 +91
- Misses 4533 4541 +8
- Partials 936 937 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (14)
WalkthroughThe PR implements an append-only MVCC design for organizational facts: adds Pydantic models 🚥 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/synthorg/memory/org/store.py (1)
612-655:⚠️ Potential issue | 🔴 CriticalRollback the transaction before re-raising write errors.
After
BEGIN IMMEDIATE, both write paths log and raise without a rollback. A failure after the transaction starts leaves the connection inside that transaction, so the next write can hitcannot start a transaction within a transactionor commit work that should have been discarded.Also applies to: 677-717
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/store.py` around lines 612 - 655, The exception handler in the transaction block around _append_to_operation_log and the INSERT into org_facts_snapshot must explicitly roll back the DB transaction before re-raising; update the except sqlite3.Error as exc block (and the analogous handler in the other block at lines ~677-717) to call await db.execute("ROLLBACK") (or await db.rollback() if the DB wrapper exposes it) prior to logging and raising OrgMemoryWriteError so the connection is not left inside an open transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/design/memory-consistency.md`:
- Around line 108-110: Update this design page to reflect that MVCC and the
associated methods now live on the OrgFactStore protocol (not
SharedKnowledgeStore): replace or reframe mentions of SharedKnowledgeStore to
OrgFactStore, move descriptions and examples of publish/retract/search_shared to
the OrgFactStore section, remove or reconcile any leftover feature-flag
language, and update the implementation note to reference SQLiteOrgFactStore as
the MVCC owner; also add a short “Deviation note” explaining why the
implementation diverged from the original SharedKnowledgeStore plan so future
work targets the correct interface (OrgFactStore and SQLiteOrgFactStore) and
update any APIs or examples that still use publish/retract/search_shared to
point to the OrgFactStore equivalents.
In `@src/synthorg/memory/org/models.py`:
- Around line 206-230: The MVCC models OperationLogEntry and
OperationLogSnapshot are missing fact metadata (category, author_is_human,
author_seniority, and the fact's original created_at) which prevents
reconstructing true point-in-time state; update the Pydantic models
OperationLogEntry and OperationLogSnapshot to add fields for category: Category
| None, author_is_human: bool | None, author_seniority: Seniority | None, and
created_at: AwareDatetime | None (matching the fact model types), then update
every place that constructs these entries (e.g., the save()/append logic that
emits OperationLogEntry and any code that builds OperationLogSnapshot) to
populate these new fields from the fact at the time of the operation so the
append-only log contains a full historical picture and snapshot_at() can rebuild
exact historical facts.
In `@src/synthorg/memory/org/store.py`:
- Around line 680-702: The retract path in delete() incorrectly copies author
metadata from org_facts_snapshot so the RETRACT operation log entry is
attributed to the previous publisher; update the call to
_append_to_operation_log in delete() so it does not clone
row["author_agent_id"]/row["author_autonomy_level"] — instead pass the actual
actor context provided to delete() (e.g., the incoming
author_agent_id/author_autonomy_level parameters or self.current actor) or
explicitly pass None if no actor is available, and remove the code that reads
author_agent_id/author_autonomy_level from the snapshot row; keep
_append_to_operation_log, org_facts_snapshot, and delete() identifiers to locate
the change.
- Around line 286-302: _tags_from_json currently swallows malformed tag entries
by filtering out non-strings and blank strings; change it to validate the parsed
list strictly and raise OrgMemoryQueryError if any element is not a non-blank
string so corrupted rows surface as errors. Specifically, in _tags_from_json
after json.loads and the list check, iterate the list and if any item is not a
str or if str(item).strip() is empty, raise OrgMemoryQueryError with a
descriptive message; only if all elements pass, return tuple(NotBlankStr(t) for
t in parsed). Ensure you reference _tags_from_json, OrgMemoryQueryError, and
NotBlankStr when locating and updating the function.
- Around line 624-645: The current INSERT OR REPLACE resets created_at on
republish; change the upsert to an INSERT ... ON CONFLICT(fact_id) DO UPDATE
that updates all mutable columns but leaves created_at untouched (i.e., don't
overwrite existing created_at). In the upsert for org_facts_snapshot (where the
diff shows the INSERT OR REPLACE and VALUES using fact.created_at), switch to
using INSERT ... VALUES (...) ON CONFLICT(fact_id) DO UPDATE SET
content=excluded.content, category=excluded.category, tags=excluded.tags,
author_agent_id=excluded.author_agent_id,
author_seniority=excluded.author_seniority,
author_is_human=excluded.author_is_human,
author_autonomy_level=excluded.author_autonomy_level, retracted_at=NULL,
version=excluded.version and do not set created_at in the DO UPDATE clause (or
use created_at=COALESCE(org_facts_snapshot.created_at, excluded.created_at) if
you must include it); update the code around the save/ upsert logic in store.py
where this INSERT OR REPLACE is implemented (the block inserting into
org_facts_snapshot).
In `@tests/unit/memory/org/test_mvcc_store.py`:
- Around line 396-423: The test test_both_operations_in_log currently uses a
single SQLiteOrgFactStore with ":memory:" and awaits two save() calls
sequentially so they never run concurrently; change it to create two
SQLiteOrgFactStore instances (e.g., store_a and store_b) pointed at the same
on-disk temporary DB path (not ":memory:"), connect both (call connect() on
each), then publish the two facts concurrently using
asyncio.gather(store_a.save(...), store_b.save(...)), then retrieve the
operation log via get_operation_log("shared-fact") and the snapshot via
get("shared-fact") to assert ordering and last-writer-wins; ensure both stores
are closed/cleaned up after the test.
- Around line 312-323: The test test_snapshot_between_publish_and_retract is
non-deterministic because it relies on asyncio.sleep and datetime.now; modify
the test to drive timestamps explicitly by either injecting a mock clock into
SQLiteOrgFactStore or by calling save/delete/snapshot_at with explicit
timestamps instead of relying on real time; specifically, update the test to
create a deterministic monotonic/time source (or patch time.monotonic and
asyncio.sleep) and pass those controlled times to SQLiteOrgFactStore (or its
methods save/delete/snapshot_at) so the mid_ts is deterministic and the
snapshot_at assertion no longer depends on scheduler timing.
In `@tests/unit/memory/org/test_store.py`:
- Around line 376-378: The test currently converts retrieved.tags to a set which
masks ordering/duplication issues; instead assert the ordered tuple directly by
replacing the set assertion with a direct tuple equality check (e.g., assert
retrieved.tags == ("core-policy", "security")) for the OrgFact.tags round-trip,
and make the same change in the new backend tags test so both verify exact tuple
equality rather than a set.
---
Outside diff comments:
In `@src/synthorg/memory/org/store.py`:
- Around line 612-655: The exception handler in the transaction block around
_append_to_operation_log and the INSERT into org_facts_snapshot must explicitly
roll back the DB transaction before re-raising; update the except sqlite3.Error
as exc block (and the analogous handler in the other block at lines ~677-717) to
call await db.execute("ROLLBACK") (or await db.rollback() if the DB wrapper
exposes it) prior to logging and raising OrgMemoryWriteError so the connection
is not left inside an open transaction.
🪄 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: 2300da23-ab74-4caa-bb8e-faf52f8cbf47
📒 Files selected for processing (11)
CLAUDE.mddocs/design/memory-consistency.mdsrc/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/store.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.pytests/unit/memory/org/test_store.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotationsin Python code -- Python 3.14 has PEP 649 native lazy annotationsUse
except A, B:syntax (no parentheses) for PEP 758 exception handling in Python 3.14All public functions and classes must have type hints; mypy strict mode is enforced
Use Google-style docstrings on all public classes and functions (enforced by ruff D rules)
Create new objects for immutability; never mutate existing ones. For non-Pydantic internal collections, use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). In ConfigDict, use allow_inf_nan=False to reject NaN/Inf in numeric fields. Use
@computed_fieldfor derived values. Use NotBlankStr for all identifier/name fields instead of manual whitespace validators.Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code over bare create_task. Prefer structured concurrency.
Line length must be 88 characters (enforced by ruff)
Functions must be less than 50 lines; files less than 800 lines
Handle errors explicitly; never silently swallow exceptions in Python code
Validate at system boundaries (user input, external APIs, config files) in Python code
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/store.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic must import logging via from synthorg.observability import get_logger then logger = get_logger(name). Never use import logging / logging.getLogger() / print() in application code.
Always use variable name 'logger' (not '_logger', not 'log') for logging instances in Python
Use event name constants from synthorg.observability.events domain-specific modules (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly: from synthorg.observability.events. import EVENT_CONSTANT
Always use structured kwargs in logging: logger.info(EVENT, key=value) -- never logger.info('msg %s', val)
All error paths must log at WARNING or ERROR with context before raising in Python code
All state transitions must log at INFO level in Python code
Use DEBUG level for object creation, internal flow, entry/exit of key functions in Python code
All provider calls go through BaseCompletionProvider which applies retry + rate limiting automatically. Never implement retry logic in driver subclasses or calling code.
RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig in Python code
Retryable errors (is_retryable=True): RateLimitError, ProviderTimeoutError, ProviderConnectionError, ProviderInternalError. Non-retryable errors raise immediately without retry.
RetryExhaustedError signals that all retries failed -- the engine layer catches this to trigger fallback chains
Rate limiter respects RateLimitError.retry_after from providers -- automatically pauses future requests
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/store.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/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/store.py
{src/**/*.py,tests/**/*.py,**/*.md,**/*.yaml,**/*.yml,**/*.toml}
📄 CodeRabbit inference engine (CLAUDE.md)
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001, large/medium/small. Vendor names only appear in: (1) Operations design page, (2) .claude/ files, (3) third-party imports, (4) provider presets in src/synthorg/providers/presets.py. Tests use test-provider, test-small-001.
Files:
src/synthorg/memory/org/hybrid_backend.pyCLAUDE.mdsrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pysrc/synthorg/observability/events/org_memory.pydocs/design/memory-consistency.mdtests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use pytest markers:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowfor test categorizationMaintain 80% minimum test coverage (enforced in CI) for Python tests
Use asyncio_mode = 'auto' in pytest configuration -- no manual
@pytest.mark.asyncioneeded for async testsTests have 30 seconds timeout per test (global in pyproject.toml). Non-default overrides like timeout(60) are allowed but timeout(30) markers are not needed.
Prefer
@pytest.mark.parametrizefor testing similar cases in Python testsUse Hypothesis for property-based testing in Python with
@given+@settings. Profiles: ci (10 examples, derandomize=True), dev (1000 examples), fuzz (10,000 examples, no deadline), extreme (500,000 examples, no deadline). Controlled via HYPOTHESIS_PROFILE env var.For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() to make them deterministic. For tasks that must block indefinitely, use asyncio.Event().wait() instead of asyncio.sleep(large_number).
Files:
tests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.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/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.py
🧠 Learnings (38)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
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 the 12 design pages.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: If implementation deviates from the design spec, alert the user and explain why. Do not silently diverge from the spec -- every deviation needs explicit user approval.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
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-08T05:29:08.143Z
Learning: At every phase of planning and implementation, be critical and 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-08T05:29:08.143Z
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-08T05:29:08.143Z
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-08T05:29:08.143Z
Learning: When Hypothesis finds a failure, fix the underlying bug and add an explicit example(...) decorator to the test so the case is permanently covered in CI. Never skip, dismiss, or ignore flaky tests.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Commit messages follow <type>: <description> format -- types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Signed commits are 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-08T05:29:08.143Z
Learning: Use branch naming convention <type>/<slug> from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
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 (Dockerfile linting), golangci-lint + go vet (CLI), no-em-dashes, no-redundant-timeout, eslint-web (web dashboard, zero warnings). Pre-push hooks: mypy type-check + pytest unit tests (affected modules only) + golangci-lint + go vet + go test (CLI) + eslint-web (web dashboard).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Autoupdate is disabled in pre-commit.ci (autoupdate_schedule: never) -- Dependabot owns hook version bumps via pre-commit ecosystem
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Use gh issue list via Bash (not MCP tools) for GitHub issue queries -- MCP list_issues has unreliable field data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Use squash merge strategy for PRs -- PR body becomes the squash commit message on main. Trailers (e.g. Release-As, Closes `#N`) must be in the PR body to land in the final commit.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Preserve existing Closes `#NNN` references in PR bodies -- never remove unless explicitly asked
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: After finishing an issue implementation, create a feature branch (<type>/<slug>), commit, and push -- do NOT create a PR automatically. Do NOT leave work uncommitted on main.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Never use gh pr create directly -- it is blocked by hookify. Always use /pre-pr-review to create PRs. For trivial/docs-only changes: /pre-pr-review quick skips agents but still runs automated checks.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: After PR exists, use /aurelio-review-pr to handle external reviewer feedback. The /commit-push-pr command is effectively blocked.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: Fix everything valid from review agents -- never skip. When review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to PR changes), fix them all. No deferring, no 'out of scope' skipping.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T05:29:08.143Z
Learning: PostToolUse hook (scripts/check_web_design_system.py) enforces web design system rules on every Edit/Write to web/src/
📚 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:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pydocs/design/memory-consistency.mdtests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/store.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use import logging / logging.getLogger() / print() in application code.
Applied to files:
CLAUDE.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: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
CLAUDE.md
📚 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 src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)`—never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-02T12:07:44.443Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:07:44.443Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`
Applied to files:
CLAUDE.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:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Pure data models, enums, and re-exports do NOT need logging
Applied to files:
src/synthorg/memory/org/__init__.py
📚 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/org/__init__.pydocs/design/memory-consistency.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`, etc.); import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`); import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly from the domain module
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-18T21:23:23.586Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T21:23:23.586Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from the domain-specific module under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly from synthorg.observability.events.<domain>.
Applied to files:
src/synthorg/observability/events/org_memory.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 src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly rather than using string literals
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 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 src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state that evolves; never mix static config fields with mutable runtime fields in one model
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/memory/org/models.py
📚 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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : For `dict`/`list` fields in frozen Pydantic models, rely on `frozen=True` for field reassignment prevention and `copy.deepcopy()` at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence)
Applied to files:
src/synthorg/memory/org/models.py
📚 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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/store.py
🔇 Additional comments (1)
src/synthorg/memory/org/hybrid_backend.py (1)
224-230: Tag metadata now survives the backend write path.Passing
request.tagsinto the persistedOrgFactcloses the metadata-loss gap betweenOrgFactWriteRequestand storage.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
src/synthorg/memory/org/store.py (1)
617-637:⚠️ Potential issue | 🟠 Major
snapshot_at()still reconstructs a projection, not the persisted fact state.
save()preservesfact.created_atinorg_facts_snapshot, but the operation log never records it and the CTE rebuildscreated_atfromMIN(timestamp)instead. Imported or backfilled facts can therefore return onecreated_atfrom live reads and another fromsnapshot_at(). The same query also drops category and author fields, so the historical snapshot still cannot reproduce anOrgFact-equivalent state. Persist the originalcreated_atin the log and carry forward the latestPUBLISHmetadata inOperationLogSnapshot.Also applies to: 669-700, 958-989
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/store.py` around lines 617 - 637, snapshot_at() currently rebuilds fact.created_at from MIN(timestamp) because save() stores created_at only in org_facts_snapshot while org_facts_operation_log insert calls (used by OperationLogSnapshot) do not persist created_at or PUBLISH metadata; update the INSERT into org_facts_operation_log to include created_at plus author/category/publish-related fields (e.g., author_agent_id, author_seniority, author_is_human, author_autonomy_level, category, and any PUBLISH-specific metadata) and then update OperationLogSnapshot’s CTE/reconstruction logic to carry forward the original created_at and the latest PUBLISH metadata (use the operation_type == PUBLISH marker to pick the most recent publish fields) so snapshot_at() reproduces an OrgFact-equivalent state rather than a projection.tests/unit/memory/org/test_mvcc_store.py (2)
312-323:⚠️ Potential issue | 🟡 MinorMake the publish/retract boundary test deterministic.
asyncio.sleep(0.01)plusdatetime.now(UTC)still leaves the midpoint dependent on scheduler timing. Patch the clock used bySQLiteOrgFactStore, or inject explicit timestamps, instead of sleeping.As per coding guidelines,
For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() for determinism instead of widening timing margins.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/memory/org/test_mvcc_store.py` around lines 312 - 323, test_snapshot_between_publish_and_retract is flaky due to using asyncio.sleep + datetime.now for the midpoint; make it deterministic by removing sleeps and either (a) constructing facts with explicit timestamps and passing those to SQLiteOrgFactStore.save/delete and then calling snapshot_at(mid_ts) with a known mid_ts, or (b) patching/injecting the store's clock (e.g., monkeypatch a clock attribute or time provider used by SQLiteOrgFactStore) so you can advance time deterministically and call save/delete/snapshot_at without real sleeps; update the test to use the chosen approach and reference the test name plus the store methods save, delete and snapshot_at.
396-423:⚠️ Potential issue | 🟠 MajorThis still never exercises concurrent writers.
Both publishes are awaited sequentially on one
:memory:connection, so theBEGIN IMMEDIATE/ version-allocation path never contends. Also,:memory:is per-connection, so even a second store here would not share state. Use two stores against the same temporary on-disk DB and run the saves withasyncio.gather(...).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/memory/org/test_mvcc_store.py` around lines 396 - 423, The test_both_operations_in_log currently uses a single SQLiteOrgFactStore(":memory:") and awaits saves sequentially, so it never triggers concurrent-writer contention; change it to create two SQLiteOrgFactStore instances pointed at the same temporary on-disk filename (not ":memory:"), call connect() on both, then run the two save(...) calls concurrently using asyncio.gather(...) (e.g., save on store_a and store_b with facts created by _make_fact and authors agent_a/agent_b), then fetch the operation log (get_operation_log) and snapshot (get) from one store and assert results; ensure both stores are closed/cleaned up after the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CLAUDE.md`:
- Line 93: Move the ORG_MEMORY MVCC constants so they sit with the rest of the
ORG_MEMORY constants instead of being appended at the end; locate the block
containing the ORG_MEMORY_* names (e.g., ORG_MEMORY_QUERY_START,
ORG_MEMORY_WRITE_COMPLETE, ORG_MEMORY_NOT_CONNECTED, etc.) and reposition the
MVCC constants (ORG_MEMORY_MVCC_PUBLISH_APPENDED,
ORG_MEMORY_MVCC_RETRACT_APPENDED, ORG_MEMORY_MVCC_SNAPSHOT_AT_QUERIED,
ORG_MEMORY_MVCC_LOG_QUERIED) immediately with that group (optionally alphabetize
or keep logical grouping) to keep all ORG_MEMORY constants together for
maintainability.
In `@src/synthorg/memory/org/store.py`:
- Around line 930-952: snapshot_at currently serializes the input timestamp with
timestamp.isoformat() which can produce non-UTC or naive ISO strings that don't
match the UTC ISO strings in the log; normalize the input to UTC first: in
snapshot_at, detect if timestamp.tzinfo is None and treat it explicitly (e.g.
attach UTC), otherwise convert with timestamp.astimezone(datetime.timezone.utc),
then serialize that UTC-aware datetime to produce query_ts used in the CTE;
update any imports if needed and keep the normalized query_ts variable name.
---
Duplicate comments:
In `@src/synthorg/memory/org/store.py`:
- Around line 617-637: snapshot_at() currently rebuilds fact.created_at from
MIN(timestamp) because save() stores created_at only in org_facts_snapshot while
org_facts_operation_log insert calls (used by OperationLogSnapshot) do not
persist created_at or PUBLISH metadata; update the INSERT into
org_facts_operation_log to include created_at plus
author/category/publish-related fields (e.g., author_agent_id, author_seniority,
author_is_human, author_autonomy_level, category, and any PUBLISH-specific
metadata) and then update OperationLogSnapshot’s CTE/reconstruction logic to
carry forward the original created_at and the latest PUBLISH metadata (use the
operation_type == PUBLISH marker to pick the most recent publish fields) so
snapshot_at() reproduces an OrgFact-equivalent state rather than a projection.
In `@tests/unit/memory/org/test_mvcc_store.py`:
- Around line 312-323: test_snapshot_between_publish_and_retract is flaky due to
using asyncio.sleep + datetime.now for the midpoint; make it deterministic by
removing sleeps and either (a) constructing facts with explicit timestamps and
passing those to SQLiteOrgFactStore.save/delete and then calling
snapshot_at(mid_ts) with a known mid_ts, or (b) patching/injecting the store's
clock (e.g., monkeypatch a clock attribute or time provider used by
SQLiteOrgFactStore) so you can advance time deterministically and call
save/delete/snapshot_at without real sleeps; update the test to use the chosen
approach and reference the test name plus the store methods save, delete and
snapshot_at.
- Around line 396-423: The test_both_operations_in_log currently uses a single
SQLiteOrgFactStore(":memory:") and awaits saves sequentially, so it never
triggers concurrent-writer contention; change it to create two
SQLiteOrgFactStore instances pointed at the same temporary on-disk filename (not
":memory:"), call connect() on both, then run the two save(...) calls
concurrently using asyncio.gather(...) (e.g., save on store_a and store_b with
facts created by _make_fact and authors agent_a/agent_b), then fetch the
operation log (get_operation_log) and snapshot (get) from one store and assert
results; ensure both stores are closed/cleaned up after the test.
🪄 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: c078f726-1258-4331-a548-5ec96a12136c
📒 Files selected for processing (7)
CLAUDE.mdsrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/store.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_mvcc_store.pytests/unit/memory/org/test_store.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). (2)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Backend
🧰 Additional context used
📓 Path-based instructions (7)
**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Always read the relevant
docs/design/page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to design pages. The design spec is the starting point for architecture, data models, and behavior.
Files:
CLAUDE.md
**/*.{py,pyi,ts,tsx,go,md}
📄 CodeRabbit inference engine (CLAUDE.md)
Commits use format
<type>: <description>. Types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook).All commits on
mainmust be GPG/SSH signed. Enforced by branch protection.Use branch naming:
<type>/<slug>from main.
Files:
CLAUDE.mdsrc/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.py
**/*.{py,pyi}
📄 CodeRabbit inference engine (CLAUDE.md)
Python 3.14+ with PEP 649 native lazy annotations. Do not use
from __future__ import annotations.Use PEP 758 except syntax:
except A, B:(no parentheses) on Python 3.14. Ruff enforces this.Include type hints on all public functions. Enable mypy strict mode for type checking.
Use Google-style docstrings on all public classes and functions. Required and enforced by ruff D rules.
Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries,
BaseTool), usecopy.deepcopy()at construction and wrap withMappingProxyTypefor read-only enforcement. Fordict/listfields in frozen Pydantic models, rely onfrozen=Truefor field reassignment prevention and usecopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).Use frozen Pydantic models for config/identity. Use separate mutable-via-copy models (via
model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.Use Pydantic v2 with
BaseModel,model_validator,computed_field, andConfigDict. Useallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation time.Use
@computed_fieldfor derived values instead of storing and validating redundant fields (e.g.TokenUsage.total_tokens).Use
NotBlankStrfromcore.typesfor all identifier/name fields, including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants, instead of manual whitespace validators.Prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_task. Existing code is being migrated incrementally.Keep functions under 50 lines and files under 800 lines.
Handle errors explicitly, never silently swallow them.
Validate at system boundaries (u...
Files:
src/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.py
src/**/*.{py,pyi}
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic MUST have:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__). Never useimport logging,logging.getLogger(), orprint()in application code (exception:observability/setup.py,observability/sinks.py,observability/syslog_handler.py, andobservability/http_handler.pymay use stdlibloggingandprint(..., file=sys.stderr)).Always use
loggeras the variable name (not_logger, notlog).Use constants from domain-specific modules under
synthorg.observability.eventsfor event names. Import directly from the domain module (e.g.from synthorg.observability.events.api import API_REQUEST_STARTED). Each domain has its own module with constants likeAPI_REQUEST_STARTED,TOOL_INVOKE_START,GIT_COMMAND_START,CONTEXT_BUDGET_FILL_UPDATED,BACKUP_STARTED,SETUP_COMPLETED,ROUTING_CANDIDATE_SELECTED,SHIPPING_HTTP_BATCH_SENT,EVAL_REPORT_COMPUTED,PROMPT_PROFILE_SELECTED,PROCEDURAL_MEMORY_START,PERF_LLM_JUDGE_STARTED,TASK_ENGINE_OBSERVER_FAILED,WORKFLOW_EXEC_COMPLETED,BLUEPRINT_INSTANTIATE_START,WORKFLOW_DEF_ROLLED_BACK,WORKFLOW_VERSION_SAVED, and memory/reporting/risk/consolidation/notification/quality/health/trajectory/coordination/web/database/terminal/sub_constraint/versioning/analytics/call_classification/quota/org_memory domain events.Use structured logging with kwargs: always
logger.info(EVENT, key=value)-- neverlogger.info("msg %s", val).Log all error paths at WARNING or ERROR with context before raising.
Log all state transitions at INFO level.
Use DEBUG log level for object creation, internal flow, and entry/exit of key functions.
All provider calls go through
BaseCompletionProviderwhich applies retry and rate limiting automatically. Never implement retry logic in driver subclasses or calling code.Set
RetryConfigandRateLimiterConfigper-provider inProviderConfig.Retryable errors (
is_retryable=True) includ...
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.py
src/**/*.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/org/hybrid_backend.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.py
tests/**/*.{py,pyi}
📄 CodeRabbit inference engine (CLAUDE.md)
Use markers:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, and@pytest.mark.slow.Maintain 80% test coverage minimum, enforced in CI.
Use
asyncio_mode = "auto"in pytest config. No manual@pytest.mark.asyncioneeded.Default test timeout is 30 seconds per test (global in
pyproject.toml). Do not add per-filepytest.mark.timeout(30)markers. Non-default overrides liketimeout(60)are allowed.Always include
-n 8when running pytest locally for parallel execution with pytest-xdist. Never run tests sequentially. CI uses-n auto.Prefer
@pytest.mark.parametrizefor testing similar cases.Use Hypothesis for property-based testing with
@givenand@settingsdecorators. Hypothesis profiles:ci(deterministic,max_examples=10+derandomize=True),dev(1000 examples),fuzz(10,000 examples, no deadline),extreme(500,000 examples, no deadline). Control viaHYPOTHESIS_PROFILEenv var..hypothesis/is gitignored. Failing examples persist to~/.synthorg/hypothesis-examples/via_WriteOnlyDatabase.When Hypothesis finds a failure, it is a real bug. Read the shrunk example, fix the underlying bug, and add an explicit
@example(...)decorator to permanently cover the case in CI. Do NOT just rerun and move on.Never skip, dismiss, or ignore flaky tests. Always fix them fully and fundamentally. For timing-sensitive tests, mock
time.monotonic()andasyncio.sleep()for determinism instead of widening timing margins. For tasks that must block indefinitely until cancelled, useasyncio.Event().wait()instead ofasyncio.sleep(large_number).
Files:
tests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.py
tests/**/*.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/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.py
🧠 Learnings (32)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts. At every phase of planning and implementation, be critical and 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-08T06:39:12.742Z
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-08T06:39:12.742Z
Learning: Pure data models, enums, and re-exports do NOT need logging.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `example-medium-001`, `example-small-001`, `large`/`medium`/`small`. Vendor names may only appear in: (1) Operations design page provider list (`docs/design/operations.md`), (2) `.claude/` skill/agent files, (3) third-party import paths/module names, (4) provider presets (`src/synthorg/providers/presets.py`). Tests must use `test-provider`, `test-small-001`, etc.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
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 (Dockerfile), golangci-lint + go vet (CLI, conditional), no-em-dashes, no-redundant-timeout, eslint-web (web dashboard, conditional).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Hookify rules committed in `.claude/hookify.*.md`: `block-pr-create` (blocks `gh pr create`, must use `/pre-pr-review`), `enforce-parallel-tests` (enforces `-n 8` with pytest), `no-cd-prefix` (blocks `cd` prefix in Bash commands), `no-local-coverage` (blocks `--cov` flags locally, CI handles coverage).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Pre-push hooks run: mypy type-check (affected modules only) + pytest unit tests (affected modules only) + golangci-lint + go vet + go test (CLI, conditional) + eslint-web (web dashboard, conditional). Fast gate before push, skipped in pre-commit.ci. Foundational module changes (core, config, observability) or conftest changes trigger full runs.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Pre-commit.ci has autoupdate disabled (`autoupdate_schedule: never`). Dependabot owns hook version bumps via the `pre-commit` ecosystem.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Use `gh issue list` via Bash when querying GitHub issues (not MCP tools) -- MCP `list_issues` has unreliable field data.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Use squash merge for PRs. PR body becomes the squash commit message on main. Trailers (e.g. `Release-As`, `Closes `#N``) must be in the PR body to land in the final commit.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Preserve existing `Closes `#NNN`` issue references in PR bodies. Never remove unless explicitly asked.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: After finishing an issue implementation, create a feature branch (`<type>/<slug>`), commit, and push. Do NOT create a PR automatically. Do NOT leave work uncommitted on main.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: Never create a PR directly with `gh pr create` (blocked by hookify). Always use `/pre-pr-review` to create PRs. It runs automated checks + review agents + fixes before creating the PR. For trivial/docs-only changes, use `/pre-pr-review quick` to skip agents but still run checks. After PR exists, use `/aurelio-review-pr` for external reviewer feedback. The `/commit-push-pr` command is effectively blocked (calls `gh pr create` internally).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: When review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and adjacent findings), fix them all. No deferring, no 'out of scope' skipping.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T06:39:12.742Z
Learning: If implementation deviates from the design spec (better approach found, scope evolved, etc.), alert the user and explain why. User decides whether to proceed or update the spec. Do NOT silently diverge. Every deviation needs explicit user approval. When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use import logging / logging.getLogger() / print() in application code.
Applied to files:
CLAUDE.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: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)`—never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.md
📚 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 src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-02T12:07:44.443Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:07:44.443Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings
Applied to files:
CLAUDE.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/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:
src/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_store.pysrc/synthorg/memory/org/store.py
📚 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/org/hybrid_backend.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 tests/**/*.py : Fix flaky tests completely and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally; mock `time.monotonic()` and `asyncio.sleep()` for determinism; use `asyncio.Event().wait()` for indefinite blocking instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to tests/**/*.py : Never skip, dismiss, or ignore flaky tests; fix them fully and fundamentally by mocking `time.monotonic()` and `asyncio.sleep()` for determinism or using `asyncio.Event().wait()` for indefinite blocking
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-07T22:12:30.142Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.142Z
Learning: Applies to tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests—always fix them fully and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins; for tasks that must block indefinitely until cancelled, use `asyncio.Event().wait()` instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-01T15:36:39.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T15:36:39.993Z
Learning: Applies to tests/**/*.py : Flaky tests: NEVER skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/store.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 src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state that evolves; never mix static config fields with mutable runtime fields in one model
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/memory/org/models.py
📚 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:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-07T22:12:30.141Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T22:12:30.141Z
Learning: Applies to src/synthorg/**/*.py : For `dict`/`list` fields in frozen Pydantic models, rely on `frozen=True` for field reassignment prevention and `copy.deepcopy()` at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence)
Applied to files:
src/synthorg/memory/org/models.py
🔇 Additional comments (3)
CLAUDE.md (1)
93-93: The MVCC event constants documented on line 93 are correctly defined insrc/synthorg/observability/events/org_memory.pyand are already in use throughout the codebase (e.g., insrc/synthorg/memory/org/store.py). The documentation is accurate.src/synthorg/memory/org/hybrid_backend.py (1)
216-223: Good:tagsnow flow into persisted facts.This closes the write-path gap between
OrgFactWriteRequestandOrgFactStore.save().tests/unit/memory/org/test_store.py (1)
362-378: Nice exact round-trip assertion fortags.Direct tuple equality keeps ordering and duplication regressions visible instead of masking them behind set semantics.
src/synthorg/memory/org/store.py
Outdated
| async def snapshot_at( | ||
| self, | ||
| timestamp: datetime, | ||
| ) -> tuple[OperationLogSnapshot, ...]: | ||
| """Point-in-time snapshot of all facts at a given timestamp. | ||
|
|
||
| Reconstructs fact state from the operation log. Active facts | ||
| have ``retracted_at=None``; retracted facts carry the retract | ||
| timestamp. | ||
|
|
||
| Args: | ||
| timestamp: UTC timestamp for the snapshot. | ||
|
|
||
| Returns: | ||
| Snapshot entries as they existed at the given time. | ||
|
|
||
| Raises: | ||
| OrgMemoryConnectionError: If not connected. | ||
| OrgMemoryQueryError: If the query fails. | ||
| """ | ||
| db = self._require_connected() | ||
| query_ts = timestamp.isoformat() | ||
| # Time-travel CTE: reconstruct fact state at a timestamp. |
There was a problem hiding this comment.
Normalize snapshot_at() inputs to UTC before comparing ISO strings.
The log stores UTC ISO strings, but this query uses whatever timestamp.isoformat() returns. An aware non-UTC input represents the same instant with different text, so the lexical <= filter can exclude rows that should match. Convert to UTC before serializing, and handle naive datetimes explicitly.
🛠️ Suggested normalization
- query_ts = timestamp.isoformat()
+ normalized_timestamp = (
+ timestamp.astimezone(UTC)
+ if timestamp.tzinfo is not None
+ else timestamp.replace(tzinfo=UTC)
+ )
+ query_ts = normalized_timestamp.isoformat()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/memory/org/store.py` around lines 930 - 952, snapshot_at
currently serializes the input timestamp with timestamp.isoformat() which can
produce non-UTC or naive ISO strings that don't match the UTC ISO strings in the
log; normalize the input to UTC first: in snapshot_at, detect if
timestamp.tzinfo is None and treat it explicitly (e.g. attach UTC), otherwise
convert with timestamp.astimezone(datetime.timezone.utc), then serialize that
UTC-aware datetime to produce query_ts used in the CTE; update any imports if
needed and keep the normalized query_ts variable name.
5fe3c69 to
dfda9d5
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/synthorg/memory/org/hybrid_backend.py (1)
167-178:⚠️ Potential issue | 🟠 MajorDon’t leak raw
OrgFactStoreexceptions from the backend API.
query()andwrite()now only handle already-normalized domain errors. Any other store-side failure escapes as a raw backend-specific exception and skips the backend’s failure path, which makes caller behavior depend on the concreteOrgFactStoreagain instead of theOrgMemoryQueryError/OrgMemoryWriteErrorcontract exposed here.As per coding guidelines, "All error paths must log at WARNING or ERROR with context before raising," and the retrieved learnings note that
memory/uses pluggable backends.Also applies to: 225-238
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/hybrid_backend.py` around lines 167 - 178, The backend currently only catches OrgMemoryQueryError from self._store.query and lets other backend-specific exceptions leak; wrap any unexpected exceptions from self._store.query and self._store.write (the calls in hybrid_backend.py) by catching Exception, logging an ERROR/WARNING with context (include the original exception info) and re-raising a normalized OrgMemoryQueryError or OrgMemoryWriteError respectively so callers see the defined contract; ensure the logger.exception / logger.error call includes descriptive context (e.g., which query/write and categories/limit) and chain the original exception when constructing the OrgMemory*Error before raising.
♻️ Duplicate comments (2)
src/synthorg/memory/org/models.py (1)
186-245:⚠️ Potential issue | 🟠 MajorThe time-travel models still don't capture a full fact version.
OperationLogEntrystill can't represent the storedOrgFact.created_at, andOperationLogSnapshotstill can't representcategoryor author metadata. That meanssnapshot_at()has to synthesize part of the state from operation timestamps and can never return the same fact shape thatget()exposes for the same historical version.Also applies to: 272-303
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/models.py` around lines 186 - 245, OperationLogEntry and OperationLogSnapshot are missing full fact-version fields so snapshot_at() cannot reconstruct the original OrgFact shape; add OrgFact.created_at to OperationLogEntry (and the corresponding field to OperationLogSnapshot), and include category plus all author metadata fields (author_agent_id, author_seniority, author_is_human, author_autonomy_level) on both OperationLogEntry and OperationLogSnapshot so snapshot_at() can return the same structure as get() for a historical version; update snapshot_at() to read these new fields instead of synthesizing them from timestamps.docs/design/memory-consistency.md (1)
109-110:⚠️ Potential issue | 🟠 MajorFinish renaming the public write APIs in this spec.
These lines move MVCC to
OrgFactStore, but the write-path section above still documentspublish()/retract(). As written, the page points readers at both the old and new interfaces. Rename those tosave()/delete(..., author=...)or add an explicit mapping here.Based on learnings: "If implementation deviates from the spec, alert the user and explain why" and "Update the relevant
docs/design/page when approved deviations occur to reflect the new reality".Also applies to: 137-140
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/design/memory-consistency.md` around lines 109 - 110, The docs currently reference both the old write API (publish(), retract()) and the new MVCC-enabled OrgFactStore APIs; update the spec text to finish the rename by replacing references to publish() and retract() with the new public methods on OrgFactStore (save() and delete(..., author=...)) or add an explicit mapping sentence that shows publish() → save() and retract() → delete(..., author=...) and mention SQLiteOrgFactStore as the MVCC implementation; ensure the write-path section and the other occurrences (around lines 137–140) are made consistent so readers aren’t pointed to both old and new interfaces.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 584-607: The RETRACT path in delete() is currently writing tags=()
to _append_to_operation_log, discarding the active snapshot's tags and breaking
the audit trail; when selecting from org_facts_snapshot (the row variable) read
its tags column (e.g., row["tags"]) and pass those tags through to
_append_to_operation_log instead of an empty tuple so the operation log entry
preserves the snapshot metadata used at retraction time (ensure any stored
format is converted to the expected tags type before calling
_append_to_operation_log and keep other parameters like fact_id,
operation_type="RETRACT", category, and author_* unchanged).
- Around line 506-538: Normalize fact.created_at to UTC before converting to
text: replace the created_at argument passed to the INSERT/UPSERT with a
UTC-normalized ISO string by ensuring fact.created_at is timezone-aware and
converted to UTC (e.g., use
fact.created_at.astimezone(datetime.timezone.utc).isoformat(), or if naive
attach UTC then isoformat). Update the created_at expression used in the
org_facts_snapshot INSERT (the tuple element where fact.created_at.isoformat()
is used) so all persisted timestamps are in UTC for correct lexical ordering.
In `@tests/unit/memory/org/test_models.py`:
- Around line 108-119: Tests only cover valid tag tuples; add parametrized tests
that assert ValidationError for tags=("",) and tags=(" ",) for both the
OrgFact construction and OrgFactWriteRequest to prevent regressions to plain
tuple[str, ...]. Update or add parameterized test functions around
test_fact_with_tags to include these invalid cases and ensure they raise
pydantic.ValidationError; reference the OrgFact and OrgFactWriteRequest models
when creating instances in the tests. Also ensure the models use NotBlankStr
from core.types for identifier/name/tag element types (including tuple variants)
instead of manual whitespace validators so the validation is enforced at the
model level.
In `@tests/unit/memory/org/test_mvcc_store.py`:
- Around line 369-375: The test currently only checks both writes were logged
and a snapshot row exists; update it to assert the snapshot equals the winning
(highest-version) log entry by: after fetching log via
store_a.get_operation_log("shared-fact") and fact via
store_a.get("shared-fact"), locate the log entry with the maximum version (or
highest sequence/timestamp field used as the version) from the `log` sequence
and assert that `fact` matches that entry (compare the same fields used for
equality in your model, e.g., value/content and version), ensuring the snapshot
reflects the last-writer-wins entry recorded in the log.
In `@tests/unit/memory/org/test_store.py`:
- Around line 146-163: The test test_save_with_agent_author is missing an
assertion for the author's autonomy level; update the test to assert that the
round-tripped fact preserves AGENT_AUTHOR.autonomy_level by checking
retrieved.author.autonomy_level == AutonomyLevel.SEMI after calling
connected_store.save(fact) and connected_store.get("f1"), ensuring the
serialization/deserialization in OrgFact (and related store methods) retains
author.autonomy_level.
---
Outside diff comments:
In `@src/synthorg/memory/org/hybrid_backend.py`:
- Around line 167-178: The backend currently only catches OrgMemoryQueryError
from self._store.query and lets other backend-specific exceptions leak; wrap any
unexpected exceptions from self._store.query and self._store.write (the calls in
hybrid_backend.py) by catching Exception, logging an ERROR/WARNING with context
(include the original exception info) and re-raising a normalized
OrgMemoryQueryError or OrgMemoryWriteError respectively so callers see the
defined contract; ensure the logger.exception / logger.error call includes
descriptive context (e.g., which query/write and categories/limit) and chain the
original exception when constructing the OrgMemory*Error before raising.
---
Duplicate comments:
In `@docs/design/memory-consistency.md`:
- Around line 109-110: The docs currently reference both the old write API
(publish(), retract()) and the new MVCC-enabled OrgFactStore APIs; update the
spec text to finish the rename by replacing references to publish() and
retract() with the new public methods on OrgFactStore (save() and delete(...,
author=...)) or add an explicit mapping sentence that shows publish() → save()
and retract() → delete(..., author=...) and mention SQLiteOrgFactStore as the
MVCC implementation; ensure the write-path section and the other occurrences
(around lines 137–140) are made consistent so readers aren’t pointed to both old
and new interfaces.
In `@src/synthorg/memory/org/models.py`:
- Around line 186-245: OperationLogEntry and OperationLogSnapshot are missing
full fact-version fields so snapshot_at() cannot reconstruct the original
OrgFact shape; add OrgFact.created_at to OperationLogEntry (and the
corresponding field to OperationLogSnapshot), and include category plus all
author metadata fields (author_agent_id, author_seniority, author_is_human,
author_autonomy_level) on both OperationLogEntry and OperationLogSnapshot so
snapshot_at() can return the same structure as get() for a historical version;
update snapshot_at() to read these new fields instead of synthesizing them from
timestamps.
🪄 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: 1dcb95dd-b09c-4464-bb97-75e621e24005
📒 Files selected for processing (14)
CLAUDE.mddocs/design/memory-consistency.mdsrc/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.pytests/unit/memory/org/test_store.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 Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotations-- Python 3.14 has PEP 649Use
except A, B:(no parentheses) syntax for exception handling in Python 3.14 per PEP 758All public functions must have type hints; use mypy strict mode for type checking
Use Google style docstrings, required on public classes and functions (enforced by ruff D rules)
Create new objects instead of mutating existing ones; for non-Pydantic internal collections use
copy.deepcopy()at construction andMappingProxyTypefor read-only enforcementUse frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state that evolves
Never mix static config fields with mutable runtime fields in one Pydantic model
Use Pydantic v2 (
BaseModel,model_validator,computed_field,ConfigDict); includeallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/InfUse
@computed_fieldfor derived values in Pydantic models instead of storing and validating redundant fields (e.g.,TokenUsage.total_tokens)Use
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 (e.g., multiple tool invocations, parallel agent calls); prefer structured concurrency over barecreate_taskKeep functions under 50 lines and files under 800 lines
Handle errors explicitly, never silently swallow them
Validate at system boundaries (user input, external APIs, config files)
Use line length of 88 characters (enforced by ruff)
Files:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_models.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowmarkers for test classificationUse
asyncio_mode = "auto"for async tests; no manual@pytest.mark.asyncioneededPrefer
@pytest.mark.parametrizefor testing similar casesTests must use
test-provider,test-small-001instead of real vendor namesUse Hypothesis for property-based testing with
@givenand@settings; configure profiles intests/conftest.py:ci(deterministic, max_examples=10, derandomize=True),dev(1000 examples),fuzz(10,000 examples, no deadline),extreme(500,000 examples, no deadline)When Hypothesis finds a failure, fix the underlying bug and add an explicit
@example(...)decorator to the test for permanent CI coverageNever skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally; for timing-sensitive tests mock
time.monotonic()andasyncio.sleep()for determinismFor tasks that must block indefinitely until cancelled, use
asyncio.Event().wait()instead ofasyncio.sleep(large_number)for cancellation-safety and no timing assumptions
Files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.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/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic must import
from synthorg.observability import get_loggerand setlogger = get_logger(__name__)Always use the variable name
logger(not_logger, notlog) for logger instancesUse vendor-agnostic names everywhere in project-owned code:
example-provider,example-large-001,example-medium-001,example-small-001, orlarge/medium/smallaliases; never use vendor names (Anthropic, OpenAI, Claude, GPT, etc.) except in: operations design page,.claude/files, third-party imports, or provider presets
Files:
src/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.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/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Never use
import logging/logging.getLogger()/print()in application code (exception:observability/setup.py,observability/sinks.py,observability/syslog_handler.py,observability/http_handler.py)Use constants from domain-specific modules under
synthorg.observability.eventsfor event names (e.g.,API_REQUEST_STARTEDfromevents.api,TOOL_INVOKE_STARTfromevents.tool)Always use structured logging with
logger.info(EVENT, key=value)format, neverlogger.info('msg %s', val)All error paths must log at WARNING or ERROR with context before raising
All state transitions must log at INFO level
Use DEBUG level for object creation, internal flow, and entry/exit of key functions
Files:
src/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
🧠 Learnings (55)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Read the relevant `docs/design/` page before implementing any feature or planning any issue
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Alert the user and explain why if implementation deviates from the design spec; do not silently diverge -- every deviation needs explicit user approval
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Present every implementation plan to the user for accept/deny before coding starts
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: At every phase of planning and implementation, be critical and actively look for ways to improve the design in the spirit of robustness, correctness, simplicity, and future-proofing
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Surface improvements as suggestions, not silent changes -- user decides whether to proceed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
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-08T11:38:12.476Z
Learning: Pure data models, enums, and re-exports do not need logging
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Maintain 80% minimum code coverage (enforced in CI)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Global test timeout is 30 seconds per test (configured in `pyproject.toml`); do not add per-file `pytest.mark.timeout(30)` markers; non-default overrides like `timeout(60)` are allowed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Always include `-n 8` when running pytest locally for parallelism with pytest-xdist; never run tests sequentially
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Control Hypothesis profile via `HYPOTHESIS_PROFILE` env var; failing examples are persisted to `~/.synthorg/hypothesis-examples/`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: CI runs 10 deterministic property test examples (`derandomize=True`); for random fuzzing locally use `HYPOTHESIS_PROFILE=dev` (1000 examples) or `HYPOTHESIS_PROFILE=fuzz` (10,000 examples, no deadline, all `given` tests)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Use commit format `<type>: <description>` with types: feat, fix, refactor, docs, test, chore, perf, ci (enforced by commitizen via commit-msg hook)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Signed commits are 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-08T11:38:12.476Z
Learning: Use branch naming format `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
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-08T11:38:12.476Z
Learning: Pre-push hooks enforce mypy type-check and pytest unit tests on affected modules, plus linting for CLI and web; foundational module or conftest changes trigger full runs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Use `gh issue list` via Bash for GitHub issue queries; MCP `list_issues` has unreliable field data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Use squash merge strategy -- PR body becomes the squash commit message on main; preserve `Closes `#NNN`` references in PR body
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: After finishing an issue implementation, create a feature branch (`<type>/<slug>`), commit, and push -- do NOT create a PR automatically; do not leave work uncommitted on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Never create a PR directly with `gh pr create` (blocked by hookify) -- always use `/pre-pr-review` to create PRs; for trivial/docs-only changes use `/pre-pr-review quick`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: After the PR exists, use `/aurelio-review-pr` to handle external reviewer feedback
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: When review agents find valid issues, fix them all -- no deferring or skipping as out of scope
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: A PostToolUse hook (`scripts/check_web_design_system.py`) enforces web design system rules on every Edit/Write to `web/src/`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Never use `cd` in Bash commands -- working directory is already at project root; use absolute paths or run commands directly; exception: `bash -c "cd <dir> && <cmd>"` is safe for tools without `-C` flag
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: Never use Bash to write or modify files -- use Write or Edit tools; do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, `python -c`, or `tee` to create or modify files
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: See `web/CLAUDE.md` for web dashboard commands, design system, and component inventory
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: See `cli/CLAUDE.md` for CLI commands, flags, and reference; key rule: use `go -C cli` (never `cd cli`)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T11:38:12.476Z
Learning: See `docs/reference/claude-reference.md` for documentation layout, Docker commands, package structure, releasing, and CI pipelines
📚 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:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_models.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/observability/events/org_memory.pydocs/design/memory-consistency.mdtests/unit/memory/org/test_store.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
📚 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:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/hybrid_backend.pydocs/design/memory-consistency.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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pydocs/design/memory-consistency.mdtests/unit/memory/org/test_store.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
📚 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:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/__init__.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/sqlite_store.py
📚 Learning: 2026-04-01T12:36:58.294Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T12:36:58.294Z
Learning: Applies to src/synthorg/**/*.py : Pure data models, enums, and re-exports do NOT need logging
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import `from synthorg.observability import get_logger` and define `logger = get_logger(__name__)`
Applied to files:
src/synthorg/memory/org/__init__.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 src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
tests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/models.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 tests/**/*.py : Fix flaky tests completely and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
src/synthorg/observability/events/org_memory.pyCLAUDE.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`); import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
src/synthorg/observability/events/org_memory.pyCLAUDE.md
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly from the domain module
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-18T21:23:23.586Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T21:23:23.586Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from the domain-specific module under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly from synthorg.observability.events.<domain>.
Applied to files:
src/synthorg/observability/events/org_memory.pyCLAUDE.md
📚 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 src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly rather than using string literals
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls
Applied to files:
src/synthorg/observability/events/org_memory.pyCLAUDE.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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
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 the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-04-08T11:07:20.359Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.359Z
Learning: If implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why -- user decides whether to proceed or update the spec. Do NOT silently diverge. When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-04-08T11:07:20.359Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.359Z
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 12 design pages
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/memory-consistency.md
📚 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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally; mock `time.monotonic()` and `asyncio.sleep()` for determinism; use `asyncio.Event().wait()` for indefinite blocking instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to tests/**/*.py : For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic. For tasks blocking indefinitely until cancelled, use `asyncio.Event().wait()` instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to tests/**/*.py : Never skip, dismiss, or ignore flaky tests; fix them fully and fundamentally by mocking `time.monotonic()` and `asyncio.sleep()` for determinism or using `asyncio.Event().wait()` for indefinite blocking
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-01T15:36:39.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T15:36:39.993Z
Learning: Applies to tests/**/*.py : Flaky tests: NEVER skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-03-31T16:09:24.320Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T16:09:24.320Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).
Applied to files:
CLAUDE.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: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code (exceptions: observability setup modules)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use import logging / logging.getLogger() / print() in application code.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to src/synthorg/**/*.py : Use structured logging: always `logger.info(EVENT, key=value)` -- never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-02T12:07:44.443Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:07:44.443Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`
Applied to files:
CLAUDE.md
📚 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 src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
CLAUDE.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 : Use structured logging: always `logger.info(EVENT, key=value)` — never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state that evolves (via `model_copy(update=...)`). Never mix static config fields with mutable runtime fields in one model
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to **/*.py : Config vs runtime state: use 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 fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
🔇 Additional comments (1)
CLAUDE.md (1)
93-93: Good update to logging event-name guidance.Line 93 now aligns with the actual
events.org_memoryinventory (including MVCC constants) and keeps the rule consistent with direct domain-constant imports.Based on learnings: Use event name constants from domain-specific modules under
synthorg.observability.eventsand import them directly.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
tests/unit/memory/org/test_mvcc_store.py (1)
369-378:⚠️ Potential issue | 🟡 MinorAssert the winning author metadata too.
This only proves
contentmatches the highest-version log entry. A regression that leavesauthor_agent_idorsenioritystale inorg_facts_snapshotwould still pass.🧪 Tighten the assertion
fact = await store_a.get("shared-fact") assert fact is not None winner = max(log, key=lambda e: e.version) assert fact.content == winner.content + assert fact.author.agent_id == winner.author_agent_id + assert fact.author.seniority == winner.author_seniority + assert fact.author.is_human == winner.author_is_human🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/memory/org/test_mvcc_store.py` around lines 369 - 378, The test currently only asserts that fact.content equals the highest-version log entry; update the assertion to also verify that the snapshot carries the winning entry's metadata by comparing fact.author_agent_id and fact.seniority to the winner's author_agent_id and seniority (use the existing log lookup via get_operation_log and the snapshot read via get in test_mvcc_store.py). Locate the winner as done with winner = max(log, key=lambda e: e.version) and add assertions that fact.author_agent_id == winner.author_agent_id and fact.seniority == winner.seniority to ensure org_facts_snapshot preserves author/seniority metadata.src/synthorg/memory/org/sqlite_store.py (1)
134-136:⚠️ Potential issue | 🟠 MajorPreserve caller tag order when serializing.
Sorting here mutates the stored value, so
get()andget_operation_log()cannot round-tripOrgFact.tagsexactly. Since the public API exposes tags as ordered tuples, the serializer should preserve that order.💡 Minimal fix
def _tags_to_json(tags: tuple[NotBlankStr, ...]) -> str: - """Serialize tags tuple to sorted JSON array.""" - return json.dumps(sorted(tags)) + """Serialize tags tuple preserving caller order.""" + return json.dumps(list(tags))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` around lines 134 - 136, The serializer _tags_to_json currently sorts the tags which mutates caller order; change it to preserve the original order by removing the sort and serializing the tags as-is (e.g., convert the tuple to a list and call json.dumps on that) so OrgFact.tags round-trips exactly; update _tags_to_json to return json.dumps(list(tags)) and ensure any callers relying on sorted output are adjusted accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 307-560: The file exceeds the 800-line limit and large functions
(save and snapshot_at) exceed 50 lines; refactor by extracting schema/DDL,
row-mapping, and time-travel reconstruction into separate modules/classes: move
SQL DDL constants (_CREATE_OPERATION_LOG_SQL, _CREATE_SNAPSHOT_SQL, _CREATE_...
etc.) and _ensure_schema into a new sqlite_schema (or SQLiteOrgSchema) unit,
move row mapping utilities used by _append_to_operation_log/save and snapshot_at
into a row_mapper (or OrgFactMapper) with functions to serialize/deserialize
tags, authors, timestamps, and fact rows, and move the time-travel replay logic
from snapshot_at into a dedicated reconstructor (e.g., OrgSnapshotReconstructor)
that can be called from snapshot_at; update SQLiteOrgFactStore to delegate to
these new units (keeping _append_to_operation_log, save, snapshot_at thin) so
functions are each under 50 lines and the file size is reduced.
- Around line 704-716: The current code uses the escaped variable for both the
LIKE filter and the INSTR() ordering parameter, causing searches with %, _, or \
to rank incorrectly; change the ORDER BY params to use the original raw text
(text) for the INSTR() relevance ordering while keeping escaped for the LIKE
clause: leave clauses.append("content LIKE ? ESCAPE '\\'") and
params.append(f"%{escaped}%") as-is, but when building order and appending the
second INSTR parameter, append the unescaped text (or its lowercased form)
instead of escaped so INSTR(LOWER(content), LOWER(?)) receives the raw search
term.
- Line 207: Update the tuple-style multi-except handlers to PEP 758
comma-separated syntax: replace constructs like "except (KeyError, ValueError,
ValidationError, OrgMemoryQueryError) as exc:" with "except KeyError,
ValueError, ValidationError, OrgMemoryQueryError as exc:" (and do the same for
the other occurrences referencing their respective exception lists). Locate
these handlers in sqlite_store.py (look for the except blocks that mention
KeyError, ValueError, ValidationError, OrgMemoryQueryError and the other
multi-except groups used inside methods of the SqliteOrgMemoryStore class) and
change each tuple-wrapped except to the comma-separated form so the code uses
the Python 3.14 PEP 758 syntax.
---
Duplicate comments:
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 134-136: The serializer _tags_to_json currently sorts the tags
which mutates caller order; change it to preserve the original order by removing
the sort and serializing the tags as-is (e.g., convert the tuple to a list and
call json.dumps on that) so OrgFact.tags round-trips exactly; update
_tags_to_json to return json.dumps(list(tags)) and ensure any callers relying on
sorted output are adjusted accordingly.
In `@tests/unit/memory/org/test_mvcc_store.py`:
- Around line 369-378: The test currently only asserts that fact.content equals
the highest-version log entry; update the assertion to also verify that the
snapshot carries the winning entry's metadata by comparing fact.author_agent_id
and fact.seniority to the winner's author_agent_id and seniority (use the
existing log lookup via get_operation_log and the snapshot read via get in
test_mvcc_store.py). Locate the winner as done with winner = max(log, key=lambda
e: e.version) and add assertions that fact.author_agent_id ==
winner.author_agent_id and fact.seniority == winner.seniority to ensure
org_facts_snapshot preserves author/seniority metadata.
🪄 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: b4fe122c-9174-48cd-ad01-af9c8437df83
📒 Files selected for processing (5)
docs/design/memory-consistency.mdsrc/synthorg/memory/org/sqlite_store.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.pytests/unit/memory/org/test_store.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 (3)
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mark unit tests with
@pytest.mark.unitMark integration tests with
@pytest.mark.integrationMark e2e tests with
@pytest.mark.e2eMark slow tests with
@pytest.mark.slowMaintain 80% minimum code coverage (enforced in CI)
Use
asyncio_mode = 'auto'in pytest config; do not add manual@pytest.mark.asynciodecoratorsSet global 30-second timeout per test in
pyproject.toml; do not add per-filepytest.mark.timeout(30)markers; non-default overrides liketimeout(60)are allowedPrefer
@pytest.mark.parametrizefor testing similar cases in Python testsUse
test-provider,test-small-001etc. in test files instead of real vendor namesUse Hypothesis for property-based testing in Python with
@given+@settingsFor timing-sensitive Python tests, mock
time.monotonic()andasyncio.sleep()to make them deterministic instead of widening timing marginsFor tasks that must block indefinitely until cancelled, use
asyncio.Event().wait()instead ofasyncio.sleep(large_number)
Files:
tests/unit/memory/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.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/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_mvcc_store.py
docs/design/**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Update the relevant
docs/design/page to reflect approved deviations from the spec
Files:
docs/design/memory-consistency.md
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotationsin Python code (Python 3.14 has PEP 649)Use
except A, B:syntax (no parentheses) per PEP 758 in Python 3.14 codeAll public functions must have type hints and comply with mypy strict mode
All public classes and functions must have Google-style docstrings (enforced by ruff D rules)
For non-Pydantic internal collections (registries, BaseTool), use
copy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcementUse frozen Pydantic models for config/identity; use separate mutable-via-copy models for runtime state
Use Pydantic v2 with
BaseModel,model_validator,computed_field,ConfigDictUse
allow_inf_nan=Falsein all PydanticConfigDictdeclarations to reject NaN/Inf in numeric fieldsUse
@computed_fieldfor derived values instead of storing + validating redundant fields in Pydantic modelsUse
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 instead of barecreate_taskKeep functions under 50 lines and files under 800 lines
Use 88 character line length (enforced by ruff)
Every module with business logic must import
from synthorg.observability import get_loggerand assignlogger = get_logger(__name__)Never use
import logging,logging.getLogger(), orprint()in application code (exceptions: observability/setup.py, observability/sinks.py, observability/syslog_handler.py, observability/http_handler.py)Always use
loggeras the variable name (not_loggerorlog)Always use event name constants from domain-specific modules under
synthorg.observability.eventsinstead of string literalsUse structured kwargs in logger calls:
logger.info(EVENT, key=value)instead oflogger.info('msg %s', val)All error paths must log at WARNING or ERROR with context before raising
All state transition...
Files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.py
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Read the relevant `docs/design/` page before implementing any feature or planning any issue
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Alert the user and explain why if implementation deviates from the design spec, do not silently diverge
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Present every implementation plan to the user for accept/deny before coding starts
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Be critical at every phase of planning and implementation, actively look for ways to improve the design
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Prioritize issues by dependency order, not priority labels
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Create new objects instead of mutating existing ones (immutability principle)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Handle errors explicitly, never silently swallow exceptions
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Validate at system boundaries (user input, external APIs, config files)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Pure data models, enums, and re-exports do NOT need logging
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Non-retryable errors raise immediately without retry
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: `RetryExhaustedError` signals all retries failed; the engine layer catches this to trigger fallback chains
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Always include `-n 8` when running pytest locally to enable parallelism with pytest-xdist
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Never run tests sequentially locally
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Control Hypothesis profile via `HYPOTHESIS_PROFILE` environment variable
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: When Hypothesis finds a failure, fix the underlying bug and add an explicit `example(...)` decorator to the test for permanent coverage in CI
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Never skip, dismiss, or ignore flaky tests; always fix them fully and fundamentally
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Commit messages must follow format `<type>: <description>` with types: feat, fix, refactor, docs, test, chore, perf, ci
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: All commits must be GPG/SSH signed on `main` (enforced by branch protection)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Use branch naming convention `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
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 (CLI), no-em-dashes, no-redundant-timeout, eslint-web (web dashboard, zero warnings)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Never use `cd` in Bash commands; use absolute paths or run commands directly; exception: `bash -c "cd <dir> && <cmd>"` is safe
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Never use Bash to write or modify files; use Write or Edit tools instead of `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, etc.
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Read the full component inventory, design token rules, and post-training references in `web/CLAUDE.md` before modifying web dashboard code
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: A PostToolUse hook (`scripts/check_web_design_system.py`) enforces design system rules on every Edit/Write to `web/src/`
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: See `cli/CLAUDE.md` for Go CLI commands, flags, and reference; use `go -C cli` (never `cd cli`)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: See `web/CLAUDE.md` for React web dashboard commands, design system, and component inventory
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: See `docs/reference/claude-reference.md` for documentation layout, Docker commands, package structure, releasing, and CI pipelines
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: After finishing an issue implementation, create a feature branch (`<type>/<slug>`), commit, and push; do NOT create a PR automatically
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Do NOT leave work uncommitted on main; branch, commit, push immediately after finishing
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Never create a PR directly with `gh pr create` (blocked by hookify); always use `/pre-pr-review` to create PRs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Use `/pre-pr-review quick` for trivial/docs-only changes to skip agents but still run automated checks
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Fix all valid issues found by review agents, including pre-existing issues in surrounding code, suggestions, and adjacent findings; never skip or defer fixes
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: Use `/aurelio-review-pr` to handle external reviewer feedback on PRs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:00:23.388Z
Learning: The `/commit-push-pr` command is effectively blocked (it calls `gh pr create` internally)
📚 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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.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 src/synthorg/**/*.py : Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier/name fields, including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants, instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. Use `computed_field` for derived values instead of storing redundant fields. Use `NotBlankStr` for all identifier/name fields.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
tests/unit/memory/org/test_models.py
📚 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:
tests/unit/memory/org/test_store.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/sqlite_store.py
📚 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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_store.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/sqlite_store.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 tests/**/*.py : Fix flaky tests completely and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally; mock `time.monotonic()` and `asyncio.sleep()` for determinism; use `asyncio.Event().wait()` for indefinite blocking instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-08T11:07:20.358Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.358Z
Learning: Applies to tests/**/*.py : For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic. For tasks blocking indefinitely until cancelled, use `asyncio.Event().wait()` instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to tests/**/*.py : Never skip, dismiss, or ignore flaky tests; fix them fully and fundamentally by mocking `time.monotonic()` and `asyncio.sleep()` for determinism or using `asyncio.Event().wait()` for indefinite blocking
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-01T15:36:39.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T15:36:39.993Z
Learning: Applies to tests/**/*.py : Flaky tests: NEVER skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-04-08T11:07:20.359Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.359Z
Learning: If implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why -- user decides whether to proceed or update the spec. Do NOT silently diverge. When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
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 the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-04-08T11:07:20.359Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T11:07:20.359Z
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 12 design pages
Applied to files:
docs/design/memory-consistency.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:
docs/design/memory-consistency.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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
docs/design/memory-consistency.mdsrc/synthorg/memory/org/sqlite_store.py
🔇 Additional comments (1)
src/synthorg/memory/org/sqlite_store.py (1)
491-545: Guard concurrent access to the sharedaiosqliteconnection or document the single-caller constraint.Each
SQLiteOrgFactStoreinstance maintains a single connection inself._db. If the same store instance handles concurrentsave()ordelete()calls from multiple coroutines, the second call'sBEGIN IMMEDIATEwill fail with "cannot start a transaction within a transaction." The application currently avoids concurrent access through single-writer patterns, but there is no explicit guard (e.g.,asyncio.Lock) or documentation of this design constraint. To prevent future misuse, either add synchronization or clearly document that store instances are single-caller only.Also applies to: 562-635
| author=author, | ||
| created_at=created_at, | ||
| ) | ||
| except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc: |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
# First, verify the file exists and check its structure
wc -l src/synthorg/memory/org/sqlite_store.pyRepository: Aureliolo/synthorg
Length of output: 105
🏁 Script executed:
# Check the specific lines mentioned in the review comment
sed -n '205,210p; 252,256p; 292,296p; 341,349p; 380,384p' src/synthorg/memory/org/sqlite_store.pyRepository: Aureliolo/synthorg
Length of output: 1238
Update exception handlers to PEP 758 syntax without parentheses.
The codebase requires comma-separated except A, B as exc: syntax per PEP 758 for Python 3.14. Convert all tuple-style multi-except handlers at lines 207, 254, 294, 343, 347, and 382:
Example conversions
- except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc:
+ except KeyError, ValueError, ValidationError, OrgMemoryQueryError as exc:- except (sqlite3.Error, OSError) as exc:
+ except sqlite3.Error, OSError as exc:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/memory/org/sqlite_store.py` at line 207, Update the tuple-style
multi-except handlers to PEP 758 comma-separated syntax: replace constructs like
"except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc:"
with "except KeyError, ValueError, ValidationError, OrgMemoryQueryError as exc:"
(and do the same for the other occurrences referencing their respective
exception lists). Locate these handlers in sqlite_store.py (look for the except
blocks that mention KeyError, ValueError, ValidationError, OrgMemoryQueryError
and the other multi-except groups used inside methods of the
SqliteOrgMemoryStore class) and change each tuple-wrapped except to the
comma-separated form so the code uses the Python 3.14 PEP 758 syntax.
| class SQLiteOrgFactStore: | ||
| """SQLite-backed organizational fact store with MVCC. | ||
|
|
||
| All writes are appended to an operation log; a materialized | ||
| snapshot table maintains the current committed state. Reads | ||
| query the snapshot. Time-travel queries replay the log. | ||
|
|
||
| Uses a separate database from the operational persistence layer | ||
| to keep institutional knowledge decoupled. | ||
|
|
||
| Args: | ||
| db_path: Path to the SQLite database file (or ``:memory:``). | ||
|
|
||
| Raises: | ||
| OrgMemoryConnectionError: If the path contains traversal. | ||
| """ | ||
|
|
||
| def __init__(self, db_path: str) -> None: | ||
| _reject_traversal(db_path) | ||
| self._db_path = db_path | ||
| self._db: aiosqlite.Connection | None = None | ||
|
|
||
| async def connect(self) -> None: | ||
| """Open the SQLite database with WAL mode and ensure schema. | ||
|
|
||
| Raises: | ||
| OrgMemoryConnectionError: If the connection fails. | ||
| """ | ||
| if self._db is not None: | ||
| return | ||
| try: | ||
| self._db = await aiosqlite.connect(self._db_path) | ||
| self._db.row_factory = aiosqlite.Row | ||
| if self._db_path != ":memory:": | ||
| await self._db.execute("PRAGMA journal_mode=WAL") | ||
| await self._ensure_schema() | ||
| except (sqlite3.Error, OSError) as exc: | ||
| if self._db is not None: | ||
| try: | ||
| await self._db.close() | ||
| except (sqlite3.Error, OSError) as close_exc: | ||
| logger.warning( | ||
| ORG_MEMORY_DISCONNECT_FAILED, | ||
| db_path=self._db_path, | ||
| reason="cleanup close during failed connect", | ||
| error=str(close_exc), | ||
| error_type=type(close_exc).__name__, | ||
| ) | ||
| self._db = None | ||
| msg = f"Failed to connect to org fact store: {exc}" | ||
| logger.exception( | ||
| ORG_MEMORY_CONNECT_FAILED, | ||
| db_path=self._db_path, | ||
| error=str(exc), | ||
| ) | ||
| raise OrgMemoryConnectionError(msg) from exc | ||
|
|
||
| async def _ensure_schema(self) -> None: | ||
| """Create tables and indexes if they don't exist.""" | ||
| db = self._require_connected() | ||
| await db.execute(_CREATE_OPERATION_LOG_SQL) | ||
| await db.execute(_CREATE_OPLOG_FACT_INDEX_SQL) | ||
| await db.execute(_CREATE_OPLOG_TIMESTAMP_INDEX_SQL) | ||
| await db.execute(_CREATE_OPLOG_COMPOSITE_INDEX_SQL) | ||
| await db.execute(_CREATE_SNAPSHOT_SQL) | ||
| await db.execute(_CREATE_SNAPSHOT_CATEGORY_INDEX_SQL) | ||
| await db.execute(_CREATE_SNAPSHOT_ACTIVE_INDEX_SQL) | ||
| await db.commit() | ||
|
|
||
| async def disconnect(self) -> None: | ||
| """Close the database connection.""" | ||
| if self._db is None: | ||
| return | ||
| try: | ||
| await self._db.close() | ||
| except (sqlite3.Error, OSError) as exc: | ||
| logger.warning( | ||
| ORG_MEMORY_DISCONNECT_FAILED, | ||
| db_path=self._db_path, | ||
| error=str(exc), | ||
| error_type=type(exc).__name__, | ||
| ) | ||
| finally: | ||
| self._db = None | ||
|
|
||
| def _require_connected(self) -> aiosqlite.Connection: | ||
| """Return the connection or raise if not connected. | ||
|
|
||
| Raises: | ||
| OrgMemoryConnectionError: If not connected. | ||
| """ | ||
| if self._db is None: | ||
| msg = "Not connected -- call connect() first" | ||
| logger.warning( | ||
| ORG_MEMORY_NOT_CONNECTED, | ||
| db_path=self._db_path, | ||
| ) | ||
| raise OrgMemoryConnectionError(msg) | ||
| return self._db | ||
|
|
||
| # ── Write operations ──────────────────────────────────────── | ||
|
|
||
| async def _append_to_operation_log( # noqa: PLR0913 | ||
| self, | ||
| db: aiosqlite.Connection, | ||
| *, | ||
| fact_id: str, | ||
| operation_type: Literal["PUBLISH", "RETRACT"], | ||
| content: str | None, | ||
| category: OrgFactCategory | None, | ||
| tags: tuple[NotBlankStr, ...], | ||
| author_agent_id: str | None, | ||
| author_seniority: SeniorityLevel | None, | ||
| author_is_human: bool, | ||
| author_autonomy_level: AutonomyLevel | None, | ||
| ) -> tuple[int, datetime]: | ||
| """Append an operation to the log within the caller's transaction. | ||
|
|
||
| Must be called inside a ``BEGIN IMMEDIATE`` transaction | ||
| managed by the caller. | ||
|
|
||
| Args: | ||
| db: Active database connection (caller-managed txn). | ||
| fact_id: Logical fact identifier. | ||
| operation_type: ``PUBLISH`` or ``RETRACT``. | ||
| content: Fact body (``None`` for RETRACT). | ||
| category: Fact category at time of operation. | ||
| tags: Metadata tags. | ||
| author_agent_id: Agent ID (``None`` for human). | ||
| author_seniority: Agent seniority level. | ||
| author_is_human: Whether the author is human. | ||
| author_autonomy_level: Autonomy level at write time. | ||
|
|
||
| Returns: | ||
| Tuple of ``(version, timestamp)``. | ||
| """ | ||
| operation_id = str(uuid.uuid4()) | ||
| now = datetime.now(UTC) | ||
| cursor = await db.execute( | ||
| "SELECT COALESCE(MAX(version), 0) " | ||
| "FROM org_facts_operation_log WHERE fact_id = ?", | ||
| (fact_id,), | ||
| ) | ||
| row = await cursor.fetchone() | ||
| # COALESCE(MAX(version), 0) always returns exactly one row. | ||
| current: int = row[0] if row is not None else 0 | ||
| next_version = current + 1 | ||
| await db.execute( | ||
| "INSERT INTO org_facts_operation_log " | ||
| "(operation_id, fact_id, operation_type, content, " | ||
| "tags, author_agent_id, author_seniority, " | ||
| "author_is_human, author_autonomy_level, category, " | ||
| "timestamp, version) " | ||
| "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||
| ( | ||
| operation_id, | ||
| fact_id, | ||
| operation_type, | ||
| content, | ||
| _tags_to_json(tags), | ||
| author_agent_id, | ||
| (author_seniority.value if author_seniority else None), | ||
| int(author_is_human), | ||
| (author_autonomy_level.value if author_autonomy_level else None), | ||
| (category.value if category else None), | ||
| now.isoformat(), | ||
| next_version, | ||
| ), | ||
| ) | ||
| return next_version, now | ||
|
|
||
| async def save(self, fact: OrgFact) -> None: | ||
| """Publish a fact: append PUBLISH to log, upsert snapshot. | ||
|
|
||
| Re-publishing a fact with the same ``fact_id`` creates a | ||
| new version in the operation log and updates the snapshot. | ||
|
|
||
| Args: | ||
| fact: The fact to persist. | ||
|
|
||
| Raises: | ||
| OrgMemoryConnectionError: If not connected. | ||
| OrgMemoryWriteError: If the save fails. | ||
| """ | ||
| db = self._require_connected() | ||
| try: | ||
| await db.execute("BEGIN IMMEDIATE") | ||
| version, _ = await self._append_to_operation_log( | ||
| db, | ||
| fact_id=fact.id, | ||
| operation_type="PUBLISH", | ||
| content=fact.content, | ||
| category=fact.category, | ||
| tags=fact.tags, | ||
| author_agent_id=fact.author.agent_id, | ||
| author_seniority=fact.author.seniority, | ||
| author_is_human=fact.author.is_human, | ||
| author_autonomy_level=fact.author.autonomy_level, | ||
| ) | ||
| await db.execute( | ||
| "INSERT INTO org_facts_snapshot " | ||
| "(fact_id, content, category, tags, " | ||
| "author_agent_id, author_seniority, author_is_human, " | ||
| "author_autonomy_level, created_at, retracted_at, " | ||
| "version) " | ||
| "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?) " | ||
| "ON CONFLICT(fact_id) DO UPDATE SET " | ||
| "content=excluded.content, " | ||
| "category=excluded.category, " | ||
| "tags=excluded.tags, " | ||
| "author_agent_id=excluded.author_agent_id, " | ||
| "author_seniority=excluded.author_seniority, " | ||
| "author_is_human=excluded.author_is_human, " | ||
| "author_autonomy_level=excluded.author_autonomy_level, " | ||
| "retracted_at=NULL, " | ||
| "version=excluded.version", | ||
| ( | ||
| fact.id, | ||
| fact.content, | ||
| fact.category.value, | ||
| _tags_to_json(fact.tags), | ||
| fact.author.agent_id, | ||
| (fact.author.seniority.value if fact.author.seniority else None), | ||
| int(fact.author.is_human), | ||
| ( | ||
| fact.author.autonomy_level.value | ||
| if fact.author.autonomy_level | ||
| else None | ||
| ), | ||
| ( | ||
| fact.created_at.astimezone(UTC).isoformat() | ||
| if fact.created_at.tzinfo is not None | ||
| else fact.created_at.replace(tzinfo=UTC).isoformat() | ||
| ), | ||
| version, | ||
| ), | ||
| ) | ||
| await db.commit() | ||
| except sqlite3.Error as exc: | ||
| with contextlib.suppress(sqlite3.Error): | ||
| await db.execute("ROLLBACK") | ||
| logger.exception( | ||
| ORG_MEMORY_WRITE_FAILED, | ||
| fact_id=fact.id, | ||
| error=str(exc), | ||
| ) | ||
| msg = f"Failed to save org fact: {exc}" | ||
| raise OrgMemoryWriteError(msg) from exc | ||
| else: | ||
| logger.info( | ||
| ORG_MEMORY_MVCC_PUBLISH_APPENDED, | ||
| fact_id=fact.id, | ||
| version=version, | ||
| ) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Split this MVCC store before it grows further.
This new module is already past the 800-line cap, and save() plus snapshot_at() are both well over the 50-line function limit. Pulling DDL/row-mapping/time-travel reconstruction into dedicated units will make this logic easier to review and evolve safely. As per coding guidelines, "src/**/*.py: Keep functions under 50 lines and files under 800 lines."
Also applies to: 771-860
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/memory/org/sqlite_store.py` around lines 307 - 560, The file
exceeds the 800-line limit and large functions (save and snapshot_at) exceed 50
lines; refactor by extracting schema/DDL, row-mapping, and time-travel
reconstruction into separate modules/classes: move SQL DDL constants
(_CREATE_OPERATION_LOG_SQL, _CREATE_SNAPSHOT_SQL, _CREATE_... etc.) and
_ensure_schema into a new sqlite_schema (or SQLiteOrgSchema) unit, move row
mapping utilities used by _append_to_operation_log/save and snapshot_at into a
row_mapper (or OrgFactMapper) with functions to serialize/deserialize tags,
authors, timestamps, and fact rows, and move the time-travel replay logic from
snapshot_at into a dedicated reconstructor (e.g., OrgSnapshotReconstructor) that
can be called from snapshot_at; update SQLiteOrgFactStore to delegate to these
new units (keeping _append_to_operation_log, save, snapshot_at thin) so
functions are each under 50 lines and the file size is reduced.
e606485 to
558def6
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
src/synthorg/memory/org/sqlite_store.py (2)
307-560: 🧹 Nitpick | 🔵 TrivialFile exceeds size limits; consider splitting.
The file is 911 lines (exceeds 800-line limit), and both
save()(~70 lines) andsnapshot_at()(~70 lines) exceed the 50-line function limit. As previously noted, extracting DDL/schema, row-mapping helpers, and time-travel CTE logic into separate modules would improve maintainability.As per coding guidelines: "Functions must be < 50 lines; files < 800 lines"
📦 Suggested module split
sqlite_schema.py: DDL constants (_CREATE_*_SQL) and_ensure_schema()sqlite_mappers.py: Row-to-model functions (_snapshot_row_to_org_fact,_row_to_operation_log_entry,_row_to_snapshot)sqlite_store.py: CoreSQLiteOrgFactStoreclass with delegated importsThis keeps each module focused and under size limits.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` around lines 307 - 560, The file exceeds the 800-line limit and large functions (notably save() and snapshot_at()) exceed the 50-line guideline; split schema DDL, row-mapping helpers, and time-travel CTE logic into separate modules and import them into SQLiteOrgFactStore. Extract the _CREATE_*_SQL constants and the logic from _ensure_schema() into a new sqlite_schema.py, move row-to-model helpers (create _snapshot_row_to_org_fact, _row_to_operation_log_entry, _row_to_snapshot) into sqlite_mappers.py, and move any complex time-travel/CTE SQL used by snapshot_at() into a dedicated helper module (e.g., sqlite_time_travel.py); update SQLiteOrgFactStore to import these symbols and delegate to them so save(), snapshot_at(), and _ensure_schema() shrink below 50 lines and the original file drops under 800 lines.
207-214:⚠️ Potential issue | 🟡 MinorUpdate exception handlers to PEP 758 comma-separated syntax.
The except clause uses parenthesized tuple syntax, but PEP 758 requires comma-separated syntax without parentheses for Python 3.14. This applies to multiple locations in the file.
As per coding guidelines: "Use PEP 758 except syntax:
except A, B:(no parentheses)—ruff enforces this on Python 3.14"🛠️ Suggested fix for Line 207
- except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc: + except KeyError, ValueError, ValidationError, OrgMemoryQueryError as exc:Same pattern applies at Lines 254, 294, 343, 347, and 382.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` around lines 207 - 214, The except clauses that catch multiple exceptions using parenthesized tuples (e.g., except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc:) must be changed to PEP 758 comma-separated syntax (e.g., except KeyError, ValueError, ValidationError, OrgMemoryQueryError as exc:). Update every such multi-exception handler in src/synthorg/memory/org/sqlite_store.py — specifically the handlers that log ORG_MEMORY_ROW_PARSE_FAILED and raise OrgMemoryQueryError (and any other occurrences catching multiple exceptions) to use the new comma-separated form while preserving the existing logger.warning(...) and raise OrgMemoryQueryError(...) behavior.src/synthorg/memory/org/models.py (1)
272-316:⚠️ Potential issue | 🟠 Major
OperationLogSnapshotis missing thecategoryfield.The
org_facts_operation_logtable storescategoryfor every operation, and theOperationLogEntrymodel includes it. However, thesnapshot_at()CTE query omitscategoryfrom its SELECT clause, andOperationLogSnapshotlacks the field entirely. This means time-travel snapshots cannot preserve or restore category state across history, limiting queries that depend on category filtering.Add
categoryto the snapshot query, model, and_row_to_snapshotconstructor.🛠️ Suggested fix
class OperationLogSnapshot(BaseModel): """Materialized snapshot row for current committed state. Represents the state of a single fact at a point in time. Active facts have ``retracted_at=None``. Attributes: fact_id: Logical fact identifier (primary key). content: Current fact body. + category: Fact category. tags: Current metadata tags. created_at: Timestamp of first PUBLISH. retracted_at: Timestamp of retraction (``None`` = active). version: Version matching most recent operation log entry. """ model_config = ConfigDict(frozen=True, allow_inf_nan=False) fact_id: NotBlankStr = Field(description="Logical fact identifier") content: NotBlankStr = Field(description="Current fact body") + category: OrgFactCategory = Field(description="Fact category") tags: tuple[NotBlankStr, ...] = Field(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/models.py` around lines 272 - 316, OperationLogSnapshot currently lacks the category field so snapshots lose fact category state; add a category: NotBlankStr field (no default) to the OperationLogSnapshot model, update the snapshot_at() CTE SELECT to include category in the materialized row, and update the _row_to_snapshot constructor (the function that builds OperationLogSnapshot from DB rows) to map the DB's category column into the new OperationLogSnapshot.category attribute so historical snapshots preserve and restore category correctly.
🤖 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/org/test_mvcc_store.py`:
- Around line 101-109: The test test_save_with_tags_records_in_log relies on the
implementation detail that tags are stored sorted; update the test to clearly
express that expectation by either adding a one-line comment referencing the
sorting behavior in _tags_to_json or changing the assertion to compare against
tuple(sorted(("security", "core-policy"))) (i.e., assert log[0].tags ==
tuple(sorted(("security", "core-policy")))), and keep references to _make_fact
and _tags_to_json so future readers know this is an intentional sorted-roundtrip
check.
---
Duplicate comments:
In `@src/synthorg/memory/org/models.py`:
- Around line 272-316: OperationLogSnapshot currently lacks the category field
so snapshots lose fact category state; add a category: NotBlankStr field (no
default) to the OperationLogSnapshot model, update the snapshot_at() CTE SELECT
to include category in the materialized row, and update the _row_to_snapshot
constructor (the function that builds OperationLogSnapshot from DB rows) to map
the DB's category column into the new OperationLogSnapshot.category attribute so
historical snapshots preserve and restore category correctly.
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 307-560: The file exceeds the 800-line limit and large functions
(notably save() and snapshot_at()) exceed the 50-line guideline; split schema
DDL, row-mapping helpers, and time-travel CTE logic into separate modules and
import them into SQLiteOrgFactStore. Extract the _CREATE_*_SQL constants and the
logic from _ensure_schema() into a new sqlite_schema.py, move row-to-model
helpers (create _snapshot_row_to_org_fact, _row_to_operation_log_entry,
_row_to_snapshot) into sqlite_mappers.py, and move any complex time-travel/CTE
SQL used by snapshot_at() into a dedicated helper module (e.g.,
sqlite_time_travel.py); update SQLiteOrgFactStore to import these symbols and
delegate to them so save(), snapshot_at(), and _ensure_schema() shrink below 50
lines and the original file drops under 800 lines.
- Around line 207-214: The except clauses that catch multiple exceptions using
parenthesized tuples (e.g., except (KeyError, ValueError, ValidationError,
OrgMemoryQueryError) as exc:) must be changed to PEP 758 comma-separated syntax
(e.g., except KeyError, ValueError, ValidationError, OrgMemoryQueryError as
exc:). Update every such multi-exception handler in
src/synthorg/memory/org/sqlite_store.py — specifically the handlers that log
ORG_MEMORY_ROW_PARSE_FAILED and raise OrgMemoryQueryError (and any other
occurrences catching multiple exceptions) to use the new comma-separated form
while preserving the existing logger.warning(...) and raise
OrgMemoryQueryError(...) behavior.
🪄 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: fc71928a-de74-41e4-9e67-5628808a8f48
📒 Files selected for processing (14)
CLAUDE.mddocs/design/memory-consistency.mdsrc/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.pytests/unit/memory/org/test_store.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 Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotations—Python 3.14 has PEP 649 native lazy annotationsUse PEP 758 except syntax:
except A, B:(no parentheses)—ruff enforces this on Python 3.14
Files:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pytests/unit/memory/org/test_mvcc_store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use markers
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowfor test classificationPrefer
@pytest.mark.parametrizefor testing similar casesProperty-based testing: use Hypothesis (
@given+@settings) in Python tests with profiles configured intests/conftest.py(ci, dev, fuzz, extreme); controlled viaHYPOTHESIS_PROFILEenv var
Files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.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/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.py
{src,tests}/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples—use generic names like
example-provider,test-provider,large/medium/small
Files:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_store.pytests/unit/memory/org/test_models.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pytests/unit/memory/org/test_mvcc_store.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
All public functions require type hints; mypy strict mode enforced
Docstrings required on public classes/functions using Google style, enforced by ruff D rules
Create new objects, never mutate existing ones; use
copy.deepcopy()at construction andMappingProxyTypefor read-only enforcementUse frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state that evolves
Use Pydantic v2 with
allow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation timeUse
@computed_fieldfor derived values instead of storing and validating redundant fieldsUse
NotBlankStr(fromcore.types) for 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 (enforced by ruff)
Functions must be < 50 lines; files < 800 lines
Handle errors explicitly, never silently swallow; validate at system boundaries (user input, external APIs, config files)
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.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/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic must have:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__)Logger variable name must always be
logger(not_logger, notlog)Event names must always use constants from domain-specific modules under
synthorg.observability.events—import directly and use structured kwargs likelogger.info(EVENT, key=value)All error paths must log at WARNING or ERROR with context before raising
All state transitions must log at INFO level
DEBUG logging for object creation, internal flow, entry/exit of key functions
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.py
🧠 Learnings (73)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: If implementation deviates from the design spec, alert the user and explain why—user decides whether to proceed or update the spec
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
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-08T12:36:56.849Z
Learning: At every phase of planning and implementation, be critical and actively look for ways to improve the design; surface improvements as suggestions, not silent changes
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
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-08T12:36:56.849Z
Learning: Pure data models, enums, and re-exports do NOT need logging
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Coverage minimum: 80% (enforced in CI)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Async tests: use `asyncio_mode = "auto"` in pytest configuration—no manual `pytest.mark.asyncio` needed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Test timeout: 30 seconds per test (global in `pyproject.toml`); do not add per-file `pytest.mark.timeout(30)` markers unless overriding to non-default
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Parallelism: always include `-n 8` when running pytest locally, never run tests sequentially
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Vendor names may only appear in: (1) Operations design page provider list, (2) `.claude/` skill/agent files, (3) third-party import paths/module names, (4) provider presets in `src/synthorg/providers/presets.py` which are user-facing runtime data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: When Hypothesis finds a failure, it is a real bug—the shrunk example is saved to `~/.synthorg/hypothesis-examples/` for analysis but is not replayed automatically; fix the underlying bug and add an explicit `example(...)` decorator
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Never skip, dismiss, or ignore flaky tests—always fix them fully and fundamentally; mock `time.monotonic()` and `asyncio.sleep()` for determinism, or use `asyncio.Event().wait()` for indefinite blocking
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Commits: use format `<type>: <description>` 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-08T12:36:56.849Z
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-08T12:36:56.849Z
Learning: Branch naming: `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
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 (Dockerfile), golangci-lint + go vet (CLI), no-em-dashes, no-redundant-timeout, eslint-web (zero warnings, web dashboard)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Hookify rules: `block-pr-create` (blocks direct `gh pr create`), `enforce-parallel-tests` (enforces `-n 8` with pytest), `no-cd-prefix` (blocks `cd` prefix in Bash), `no-local-coverage` (blocks `--cov` flags locally)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Pre-push hooks: mypy type-check (affected modules) + pytest unit tests (affected modules) + golangci-lint + go vet + go test (CLI) + eslint-web (dashboard); foundational module changes (core, config, observability) or conftest changes trigger full runs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Pre-commit.ci: autoupdate disabled (`autoupdate_schedule: never`)—Dependabot owns hook version bumps via `pre-commit` ecosystem
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: GitHub issue queries: use `gh issue list` via Bash (not MCP tools)—MCP `list_issues` has unreliable field data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Merge strategy: squash merge—PR body becomes the squash commit message on main; trailers (e.g. `Release-As`, `Closes `#N``) must be in the PR body to land in the final commit
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Preserve existing `Closes `#NNN`` references in PR issue references—never remove unless explicitly asked
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: After finishing an issue implementation: always create a feature branch (`<type>/<slug>`), commit, and push—do NOT create a PR automatically
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Do NOT leave work uncommitted on main—branch, commit, push immediately after finishing
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Never create a PR directly—`gh pr create` is blocked by hookify; always use `/pre-pr-review` to create PRs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: For trivial/docs-only changes: use `/pre-pr-review quick` to skip agents but still run automated checks
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: After the PR exists, use `/aurelio-review-pr` to handle external reviewer feedback
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Fix all valid issues found by review agents—never skip, no deferring, no 'out of scope' skipping; include pre-existing issues in surrounding code and adjacent findings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Never use `cd` in Bash commands—working directory is already set to project root; use absolute paths or run commands directly; exception: `bash -c "cd <dir> && <cmd>"` is safe (child process)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: Never use Bash to write or modify files—use Write or Edit tools; do not use `cat >`, `cat << EOF`, `echo >`, `echo >>`, `sed -i`, or `tee` to create/modify files (read-only uses are fine)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T12:36:56.849Z
Learning: See `web/CLAUDE.md` for the full component inventory, design token rules, and post-training references; a PostToolUse hook (`scripts/check_web_design_system.py`) enforces these rules on every Edit/Write to `web/src/`
📚 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:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_store.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.py
📚 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:
tests/unit/memory/org/test_factory.pysrc/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pydocs/design/memory-consistency.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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/sqlite_store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/store.pysrc/synthorg/memory/org/sqlite_store.py
📚 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:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/models.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: All project conventions, commands, and standards are defined in CLAUDE.md - refer to it for project structure, package layout, code conventions, quick commands, git workflow, testing standards, design specifications, logging, resilience, and security patterns
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
CLAUDE.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: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to src/synthorg/**/*.py : Always use structured kwargs in logger calls (e.g., `logger.info(EVENT, key=value)`) never format strings (e.g., `logger.info('msg %s', val)`).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-02T12:07:44.443Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:07:44.443Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).
Applied to files:
CLAUDE.md
📚 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 src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
CLAUDE.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 : Use structured logging: always `logger.info(EVENT, key=value)` — never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Structured kwargs in logging: always `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to src/synthorg/**/*.py : Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-04-01T12:36:58.294Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T12:36:58.294Z
Learning: Applies to src/synthorg/**/*.py : Pure data models, enums, and re-exports do NOT need logging
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import `from synthorg.observability import get_logger` and define `logger = get_logger(__name__)`
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to {pyproject.toml,src/synthorg/__init__.py} : Update version in `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import logger via `from synthorg.observability import get_logger` and initialize with `logger = get_logger(__name__)`
Applied to files:
src/synthorg/memory/org/__init__.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 src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
src/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly from the domain module
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`); import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-18T21:23:23.586Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T21:23:23.586Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from the domain-specific module under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly from synthorg.observability.events.<domain>.
Applied to files:
src/synthorg/observability/events/org_memory.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 src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly rather than using string literals
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`) instead of string literals.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls
Applied to files:
src/synthorg/observability/events/org_memory.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 tests/**/*.py : Fix flaky tests completely and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.py
📚 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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
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 the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.{py,ts,tsx,js,go} : If implementation deviates from the design spec (better approach found, scope evolved, etc.), alert the user and explain why -- user decides whether to proceed or update the spec. Do NOT silently diverge -- every deviation needs explicit user approval.
Applied to files:
docs/design/memory-consistency.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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.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 src/synthorg/**/*.py : Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier/name fields, including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants, instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier and name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config and identity data. Use separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Applied to files:
src/synthorg/memory/org/models.py
📚 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/core/**/*.py : Core module must contain shared domain models, base classes, resilience config (RetryConfig, RateLimiterConfig)
Applied to files:
src/synthorg/memory/org/models.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) for PEP 758 exception syntax -- ruff enforces this on Python 3.14.
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 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: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally; mock `time.monotonic()` and `asyncio.sleep()` for determinism; use `asyncio.Event().wait()` for indefinite blocking instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to tests/**/*.py : Never skip, dismiss, or ignore flaky tests; fix them fully and fundamentally by mocking `time.monotonic()` and `asyncio.sleep()` for determinism or using `asyncio.Event().wait()` for indefinite blocking
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to tests/**/*.py : Never skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic. For tasks that must block indefinitely, use `asyncio.Event().wait()` instead of `asyncio.sleep(large_number)`.
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-01T15:36:39.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T15:36:39.993Z
Learning: Applies to tests/**/*.py : Flaky tests: NEVER skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
src/synthorg/memory/org/models.py (1)
186-246:⚠️ Potential issue | 🟠 Major
snapshot_at()still cannot reconstruct the original fact timestamp.
OperationLogEntrystill has no way to carryOrgFact.created_at. Insrc/synthorg/memory/org/sqlite_store.py,save()persistsfact.created_atonly inorg_facts_snapshot, whilesnapshot_at()rebuildscreated_atfrom operation-logtimestamps. Any backfilled/imported fact whose creation time differs from publish time will therefore come back with the wrong historicalcreated_at. Persist the immutable sourcecreated_atin the log and have time-travel read that instead of inferring it from write timestamps.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/models.py` around lines 186 - 246, OperationLogEntry currently lacks the immutable OrgFact.created_at so snapshot_at() reconstructs created_at from operation timestamps; add a created_at: AwareDatetime | None Field to OperationLogEntry (frozen model_config remains) and update sqlite_store.save() to persist fact.created_at into the operation log row (in addition to org_facts_snapshot), then change snapshot_at() to read created_at from the OperationLogEntry (falling back to timestamp only if created_at is null) so historical facts preserve their original creation time.src/synthorg/memory/org/sqlite_store.py (1)
207-207: 🛠️ Refactor suggestion | 🟠 MajorRewrite the tuple-style multi-
exceptclauses to PEP 758 syntax.This file still uses
except (A, B) as exc, which does not match the repo’s required Python 3.14 style and will keep Ruff flagging these handlers.#!/bin/bash rg -n 'except \(' src/synthorg/memory/org/sqlite_store.pyExample conversion
- except (sqlite3.Error, OSError) as exc: + except sqlite3.Error, OSError as exc:As per coding guidelines, "
**/*.py: Useexcept A, B:(no parentheses) for PEP 758 except syntax -- ruff enforces this on Python 3.14`."Also applies to: 254-255, 295-296, 344-348, 383-383
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` at line 207, Replace tuple-style except clauses like "except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc" with PEP 758 syntax by removing the parentheses and comma-separating exception names: "except KeyError, ValueError, ValidationError, OrgMemoryQueryError as exc". Apply the same change for the other occurrences noted (the handlers involving the same pattern around the other blocks) so each multi-exception handler uses the new "except A, B, C as exc" form.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 587-629: The code in the delete flow can raise non-sqlite
exceptions when parsing the selected row (OrgFactCategory(row["category"]) or
_tags_from_json(row["tags"])) before _append_to_operation_log is called, leaving
the DB transaction open; update the error handling so any exception during row
parsing or subsequent steps triggers a rollback and is converted to an
OrgMemoryWriteError. Concretely, wrap the SELECT/row
parsing/_append_to_operation_log/UPDATE sequence in a try/except Exception block
(or add an additional broad except around the parsing and call sites) that calls
await db.execute("ROLLBACK") inside a contextlib.suppress(sqlite3.Error), logs
via logger.exception(ORG_MEMORY_WRITE_FAILED, fact_id=fact_id, error=str(exc)),
and re-raises as OrgMemoryWriteError (like the existing sqlite3.Error handler)
so malformed snapshot rows no longer leave the connection in a transaction;
reference the _append_to_operation_log, OrgFactCategory, _tags_from_json, and
logger.exception usages to locate where to add this handling.
- Around line 325-328: Init currently sets up _db_path and _db but lacks a write
lock; add an asyncio.Lock instance (e.g., self._write_lock = asyncio.Lock()) in
__init__ of the SQLite store class and then guard all write and
read-modify-write methods (at minimum save() and delete(), and any other methods
that perform BEGIN/COMMIT sequences) by wrapping their transaction bodies with
"async with self._write_lock:" to prevent interleaving of BEGIN/COMMIT across
coroutines, following the same pattern used in SQLitePersistenceBackend and
SQLiteDecisionRepository.
---
Duplicate comments:
In `@src/synthorg/memory/org/models.py`:
- Around line 186-246: OperationLogEntry currently lacks the immutable
OrgFact.created_at so snapshot_at() reconstructs created_at from operation
timestamps; add a created_at: AwareDatetime | None Field to OperationLogEntry
(frozen model_config remains) and update sqlite_store.save() to persist
fact.created_at into the operation log row (in addition to org_facts_snapshot),
then change snapshot_at() to read created_at from the OperationLogEntry (falling
back to timestamp only if created_at is null) so historical facts preserve their
original creation time.
In `@src/synthorg/memory/org/sqlite_store.py`:
- Line 207: Replace tuple-style except clauses like "except (KeyError,
ValueError, ValidationError, OrgMemoryQueryError) as exc" with PEP 758 syntax by
removing the parentheses and comma-separating exception names: "except KeyError,
ValueError, ValidationError, OrgMemoryQueryError as exc". Apply the same change
for the other occurrences noted (the handlers involving the same pattern around
the other blocks) so each multi-exception handler uses the new "except A, B, C
as exc" form.
🪄 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: 0be8708a-8b0d-407d-9dcf-cad79b2e8eb0
📒 Files selected for processing (3)
src/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pytests/unit/memory/org/test_models.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 Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use
from __future__ import annotations-- Python 3.14 has PEP 649 native lazy annotationsUse
except A, B:(no parentheses) for PEP 758 except syntax -- ruff enforces this on Python 3.14Type hints: all public functions must have type hints, enforce mypy strict mode
Docstrings: Google style, required on public classes and functions (enforced by ruff D rules)
Immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections (registries, BaseTool), use
copy.deepcopy()at construction plusMappingProxyTypewrapping for read-only enforcementFor
dict/listfields in frozen Pydantic models, rely onfrozen=Truefor field reassignment prevention andcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization)Config vs runtime state: use frozen Pydantic models for config/identity; separate mutable-via-copy models (using
model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one modelUse Pydantic v2 (
BaseModel,model_validator,computed_field,ConfigDict). In allConfigDictdeclarations, useallow_inf_nan=Falseto rejectNaN/Infin numeric fields at validation timeUse
@computed_fieldfor derived values instead of storing and validating redundant fields (e.g.,TokenUsage.total_tokens)Use
NotBlankStr(fromcore.types) for all identifier/name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validatorsFor async concurrency, prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_taskLine length: 88 characters (ruff enforced)
Functions must be less than 50 lines, files less than 800 lines
Handle errors explicitly, never silently swallow
Vali...
Files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/models.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use pytest markers:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowCoverage: 80% minimum (enforced in CI)
Async tests:
asyncio_mode = "auto"in pytest config -- no manual@pytest.mark.asyncioneededTest timeout: 30 seconds per test (global in
pyproject.toml). Do not add per-filepytest.mark.timeout(30)markers; non-default overrides liketimeout(60)are allowedAlways include
-n 8when running pytest locally for parallelism via pytest-xdist. Never run tests sequentially. CI uses-n autoPrefer
@pytest.mark.parametrizefor testing similar casesNever use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests. Use generic names:
test-provider,test-small-001,test-medium-001,test-large-001Use Hypothesis for property-based testing with
@givenand@settingsdecorators. Use pytest profiles:ci(deterministic,max_examples=10,derandomize=True),dev(1000 examples),fuzz(10,000 examples, no deadline),extreme(500,000 examples, no deadline). Control viaHYPOTHESIS_PROFILEenv varHypothesis workflow: CI runs 10 deterministic examples per property test. When Hypothesis finds a failure, fix the underlying bug and add an explicit
@example(...)decorator to permanently cover the case in CI. Do NOT just rerun and move onNever skip, dismiss, or ignore flaky tests. Always fix them fully and fundamentally. For timing-sensitive tests, mock
time.monotonic()andasyncio.sleep()to make them deterministic. For tasks blocking indefinitely until cancelled, useasyncio.Event().wait()instead ofasyncio.sleep(large_number)
Files:
tests/unit/memory/org/test_models.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/org/test_models.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic MUST have:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__)Never use
import logging/logging.getLogger()/print()in application code. Exceptions:observability/setup.py,observability/sinks.py,observability/syslog_handler.py, andobservability/http_handler.pymay use stdlibloggingandprint(..., file=sys.stderr)for handler construction and bootstrapLogging variable name: always
logger(not_logger, notlog)Event names: always use constants from domain-specific modules under
synthorg.observability.events(import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT). Comprehensive list includes:API_REQUEST_STARTEDfromevents.api,TOOL_INVOKE_STARTfromevents.tool,GIT_COMMAND_STARTfromevents.git, and many others across all domain modulesStructured logging kwargs: always use
logger.info(EVENT, key=value)-- neverlogger.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 logging is appropriate for object creation, internal flow, and entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging
All provider calls go through
BaseCompletionProviderwhich applies retry and rate limiting automatically. Never implement retry logic in driver subclasses or calling codeRetryConfig and RateLimiterConfig are set per-provider in
ProviderConfigRetryable errors (
is_retryable=True) include:RateLimitError,ProviderTimeoutError,ProviderConnectionError,ProviderInternalError. Non-retryable errors raise immediately
RetryExhaustedErrorsignals that all retries failed -- the engine layer catches this to trigger fallback chainsThe rate limiter respects
RateLimitError.retry_afterfrom providers -- automatically pauses future requestsNever use real vendor names (Anthropic, OpenAI, Claude, GPT, etc...
Files:
src/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/models.py
src/**/*.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/org/sqlite_store.pysrc/synthorg/memory/org/models.py
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Alert the user and explain why if implementation deviates from the design spec (better approach found, scope evolved, etc.) -- user decides whether to proceed or update the spec. Never silently diverge
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
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-08T13:11:06.754Z
Learning: At every phase of planning and implementation, be critical -- actively look for ways to improve the design in the spirit of robustness, correctness, simplicity, and future-proofing. Surface improvements as suggestions, not silent changes
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
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-08T13:11:06.754Z
Learning: Never use `cd` in Bash commands. The working directory is already set to the project root. Use absolute paths or run commands directly. Exception: `bash -c "cd <dir> && <cmd>"` is safe (runs in a child process, no cwd side effects)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
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`, `python -c "open(...).write(...)"`, or `tee` to create or modify files
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Branch naming: `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
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 (Dockerfile linting), golangci-lint + go vet (CLI), no-em-dashes, no-redundant-timeout, eslint-web (web dashboard)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Hookify rules enforce: `block-pr-create` (blocks direct `gh pr create`, must use `/pre-pr-review`), `enforce-parallel-tests` (enforces `-n 8` with pytest), `no-cd-prefix` (blocks `cd` prefix in Bash commands), `no-local-coverage` (blocks `--cov` flags locally)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
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 (web dashboard). Foundational module changes (core, config, observability) or conftest changes trigger full runs
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Pre-commit.ci: autoupdate disabled (`autoupdate_schedule: never`) -- Dependabot owns hook version bumps via `pre-commit` ecosystem
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: GitHub issue queries: use `gh issue list` via Bash (not MCP tools) -- MCP `list_issues` has unreliable field data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Merge strategy: squash merge -- PR body becomes the squash commit message on main. Trailers (e.g., `Release-As`, `Closes `#N``) must be in the PR body to land in the final commit
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: PR issue references: preserve existing `Closes `#NNN`` references in PR bodies -- never remove unless explicitly asked
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: After finishing an issue implementation: always create a feature branch (`<type>/<slug>`), commit, and push -- do NOT create a PR automatically. Do NOT leave work uncommitted on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Never create a PR directly with `gh pr create` (blocked by hookify). Always use `/pre-pr-review` to create PRs -- it runs automated checks + review agents + fixes before creating the PR. For trivial/docs-only changes: `/pre-pr-review quick` skips agents but still runs automated checks
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: After the PR exists, use `/aurelio-review-pr` to handle external reviewer feedback. The `/commit-push-pr` command is effectively blocked (it calls `gh pr create` internally)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T13:11:06.754Z
Learning: Fix everything valid in PR review -- never skip valid issues found by review agents, including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes
📚 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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.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 src/synthorg/**/*.py : Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier/name fields, including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants, instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier and name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/sqlite_store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/sqlite_store.py
📚 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:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) for PEP 758 exception syntax -- ruff enforces this on Python 3.14.
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 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: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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 src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config and identity data. Use separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to **/*.py : Config vs runtime state: use 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 fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
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 `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 596-651: The delete() block opens a transaction with "BEGIN
IMMEDIATE" but doesn't handle asyncio.CancelledError, which can leave the
transaction open; add an explicit "except asyncio.CancelledError" handler before
the existing except tuple that calls the same rollback logic (use
contextlib.suppress to await db.execute("ROLLBACK")), then re-raise the
CancelledError so cancellation propagates; keep the existing exception handler
for sqlite3.Error/ValueError/OrgMemoryQueryError intact and reference the same
symbols (_append_to_operation_log, ORG_MEMORY_WRITE_FAILED, logger) when placing
the new handler.
🪄 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: abac9ab8-5cbc-4cdd-ab75-96d6bdcb8532
📒 Files selected for processing (1)
src/synthorg/memory/org/sqlite_store.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 Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Always read the relevant
docs/design/page before implementing any feature or planning any issue. The design spec is the starting point for architecture, data models, and behaviorIf implementation deviates from the design spec (better approach found, scope evolved, etc.), alert the user and explain why -- user decides whether to proceed or update the spec. Do NOT silently diverge -- every deviation needs explicit user approval
When a spec topic is referenced (e.g. 'the Agents page' or 'the Engine page's Crash Recovery section'), read the relevant
docs/design/page before codingWhen approved deviations occur, update the relevant
docs/design/page to reflect the new realityCommits must follow format:
<type>: <description>where types are feat, fix, refactor, docs, test, chore, perf, ci -- enforced by commitizen (commit-msg hook)All commits must be GPG/SSH signed (required on
mainvia branch protection)
Files:
src/synthorg/memory/org/sqlite_store.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotations-- Python 3.14 has PEP 649 native lazy annotationsUse PEP 758 except syntax: use
except A, B:(no parentheses) -- ruff enforces this on Python 3.14All public functions must have type hints and docstrings in Google style
All public classes must have Google-style docstrings
Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries,
BaseTool), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcementFor
dict/listfields in frozen Pydantic models, rely onfrozen=Truefor field reassignment prevention andcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence)Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using
model_copy(update=...)) for runtime state that evolves (e.g. agent execution state, task progress). Never mix static config fields with mutable runtime fields in one modelUse Pydantic v2 (
BaseModel,model_validator,computed_field,ConfigDict). Useallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation timeUse
@computed_fieldfor derived values instead of storing + validating redundant fields (e.g.TokenUsage.total_tokens)Use
NotBlankStr(fromcore.types) for all identifier/name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validatorsPrefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over barecreate_taskLine length must be 88 characters (enforced by ruff)
Functions must be less than 50 lines; files must be less than 800 lines
Handle errors explicitly; never silently swallow exceptions
Validate at system boundaries (user input,...
Files:
src/synthorg/memory/org/sqlite_store.py
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names:
example-provider,example-large-001,example-medium-001,example-small-001,large/medium/smallas aliases. Vendor names may only appear in: (1) Operations design page provider list (docs/design/operations.md), (2).claude/skill/agent files, (3) third-party import paths/module names, (4) provider presets (src/synthorg/providers/presets.py)
Files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.py
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Never use Bash to write or modify files -- use the Write or Edit tools. Do not use
cat >,cat << EOF,echo >,echo >>,sed -i, orteeto create/modify files. Read-only/inspection uses like piping to stdout are fine
Files:
src/synthorg/memory/org/sqlite_store.py
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:12:38.432Z
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-08T14:12:38.432Z
Learning: At every phase of planning and implementation, be critical -- actively look for ways to improve the design in the spirit of what we're building (robustness, correctness, simplicity, future-proofing where it's free)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:12:38.432Z
Learning: Surface improvements as suggestions, not silent changes -- user decides
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:12:38.432Z
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-08T14:12:38.432Z
Learning: Every implementation plan must be presented to the user for accept/deny before coding starts. At every phase be critical and surface improvements as suggestions. Prioritize issues by dependency order, not priority labels
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:12:38.432Z
Learning: Use feature branches `<type>/<slug>` from main. After finishing an issue implementation, create a feature branch, commit, and push -- do NOT create a PR automatically. Never leave work uncommitted on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:12:38.432Z
Learning: Never create a PR directly using `gh pr create` (blocked by hookify). Always use `/pre-pr-review` to create PRs. For trivial/docs-only changes use `/pre-pr-review quick`. After the PR exists, use `/aurelio-review-pr` for external reviewer feedback
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T14:12:38.432Z
Learning: When review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes), fix them all. No deferring, no 'out of scope' skipping
📚 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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/sqlite_store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
src/synthorg/memory/org/sqlite_store.py
📚 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:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 Learning: 2026-04-08T12:31:46.839Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T12:31:46.839Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) for PEP 758 exception syntax -- ruff enforces this on Python 3.14.
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 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: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.py
🔇 Additional comments (9)
src/synthorg/memory/org/sqlite_store.py (9)
208-208: PEP 758 exception syntax still uses parentheses.This was previously flagged. The codebase requires comma-separated
except A, B, C as exc:syntax per PEP 758 for Python 3.14.
787-883: LGTM!The time-travel CTE correctly reconstructs point-in-time state:
- Uses
ROW_NUMBER() OVER (PARTITION BY fact_id ORDER BY version DESC)to find the latest operation per fact at the query timestamp.- Falls back to the most recent
PUBLISHforcontent/category/tagswhen the latest operation isRETRACT.- Derives
created_atfrom the earliestPUBLISHtimestamp.The function length exceeds guidelines but was already flagged in a previous review.
1-46: LGTM!The imports are well-organized. Observability setup correctly uses
get_logger(__name__)with the properloggervariable name, and event constants are imported from the domain-specific module.
48-108: LGTM!The schema design is solid:
- Append-only operation log with
UNIQUE(fact_id, version)enforces version monotonicity.- Partial index
idx_snapshot_activeonretracted_at IS NULLoptimizes active-fact reads.- Composite index
idx_oplog_ts_factsupports efficient time-travel queries.
218-304: LGTM!Row deserialization helpers properly handle nullable fields, parse timestamps with UTC fallback, and wrap all conversion errors into
OrgMemoryQueryErrorwith appropriate logging.
326-331: LGTM!The
asyncio.Lockfor write serialization is properly initialized. Path traversal validation in__init__provides defense against malicious paths.
332-394: LGTM!Connection lifecycle management is robust:
- WAL mode is correctly skipped for
:memory:databases.- Schema creation is idempotent with
IF NOT EXISTS.- Failed connections are properly cleaned up with the connection closed and set to
None.- Disconnect logs errors but still clears state in
finally.
655-783: LGTM!Read operations correctly:
- Filter on
retracted_at IS NULLto return only active facts per the protocol contract.- Use parameterized queries throughout to prevent SQL injection.
- Use raw
text(not escaped) forINSTR()relevance ordering while using escaped text forLIKEfiltering.
926-934: LGTM!Properties are simple and correct.
| async with self._write_lock: | ||
| try: | ||
| await db.execute("BEGIN IMMEDIATE") | ||
| cursor = await db.execute( | ||
| "SELECT fact_id, category, tags " | ||
| "FROM org_facts_snapshot " | ||
| "WHERE fact_id = ? " | ||
| "AND retracted_at IS NULL", | ||
| (fact_id,), | ||
| ) | ||
| row = await cursor.fetchone() | ||
| if row is None: | ||
| await db.execute("ROLLBACK") | ||
| return False | ||
| version, now = await self._append_to_operation_log( | ||
| db, | ||
| fact_id=fact_id, | ||
| operation_type="RETRACT", | ||
| content=None, | ||
| category=( | ||
| OrgFactCategory(row["category"]) if row["category"] else None | ||
| ), | ||
| tags=_tags_from_json(row["tags"]), | ||
| author_agent_id=author.agent_id, | ||
| author_seniority=author.seniority, | ||
| author_is_human=author.is_human, | ||
| author_autonomy_level=author.autonomy_level, | ||
| ) | ||
| await db.execute( | ||
| "UPDATE org_facts_snapshot " | ||
| "SET retracted_at = ?, version = ? " | ||
| "WHERE fact_id = ?", | ||
| (now.isoformat(), version, fact_id), | ||
| ) | ||
| await db.commit() | ||
| except ( | ||
| sqlite3.Error, | ||
| ValueError, | ||
| OrgMemoryQueryError, | ||
| ) as exc: | ||
| with contextlib.suppress(sqlite3.Error): | ||
| await db.execute("ROLLBACK") | ||
| logger.exception( | ||
| ORG_MEMORY_WRITE_FAILED, | ||
| fact_id=fact_id, | ||
| error=str(exc), | ||
| ) | ||
| msg = f"Failed to delete org fact: {exc}" | ||
| raise OrgMemoryWriteError(msg) from exc | ||
| else: | ||
| logger.info( | ||
| ORG_MEMORY_MVCC_RETRACT_APPENDED, | ||
| fact_id=fact_id, | ||
| version=version, | ||
| ) | ||
| return True |
There was a problem hiding this comment.
Same cancellation gap applies to delete().
The except block doesn't catch asyncio.CancelledError, so a cancellation after BEGIN IMMEDIATE leaves the transaction open. Apply the same fix as suggested for save().
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/memory/org/sqlite_store.py` around lines 596 - 651, The delete()
block opens a transaction with "BEGIN IMMEDIATE" but doesn't handle
asyncio.CancelledError, which can leave the transaction open; add an explicit
"except asyncio.CancelledError" handler before the existing except tuple that
calls the same rollback logic (use contextlib.suppress to await
db.execute("ROLLBACK")), then re-raise the CancelledError so cancellation
propagates; keep the existing exception handler for
sqlite3.Error/ValueError/OrgMemoryQueryError intact and reference the same
symbols (_append_to_operation_log, ORG_MEMORY_WRITE_FAILED, logger) when placing
the new handler.
a249cc1 to
0ebd038
Compare
…odel (Phase 1.5) Replace SQLiteOrgFactStore internals with append-only operation log + materialized snapshot tables (D26). All writes append to org_facts_operation_log; a denormalized org_facts_snapshot table maintains the current committed state for fast reads. Key changes: - Add operation_log and snapshot tables (replace old org_facts table) - save() appends PUBLISH to log + upserts snapshot - delete() appends RETRACT to log + marks snapshot retracted_at - get()/query()/list_by_category() filter retracted_at IS NULL - Add snapshot_at(timestamp) for point-in-time queries - Add get_operation_log(fact_id) for audit trail - Add autonomy_level to OrgFactAuthor - Add tags to OrgFact and OrgFactWriteRequest - Wire tags/autonomy_level through HybridPromptRetrievalBackend - Add MVCC observability event constants - Add OperationLogEntry and OperationLogSnapshot models - 138 org memory tests (all passing) Spec deviations (user-approved): - No feature flag (pre-alpha, MVCC is the only implementation) - Time-travel methods on OrgFactStore, not SharedKnowledgeStore (Mem0 backend is a separate protocol) Closes #1130
- Add content-operation alignment validator to OperationLogEntry (PUBLISH requires content, RETRACT requires None) - Add created_at <= retracted_at validator to OperationLogSnapshot - Replace silent fallback in _tags_from_json with OrgMemoryQueryError - Add explicit BEGIN IMMEDIATE transactions in save() and delete() - Update memory-consistency.md: remove feature flag, clarify OrgFactStore - Add MVCC event constants to CLAUDE.md logging inventory Pre-reviewed by 6 agents, 7 findings addressed
…and local agents Critical fixes: - Add explicit ROLLBACK on save/delete transaction errors (Gemini, Copilot, CodeRabbit, local agents) - Preserve original created_at on republish via ON CONFLICT DO UPDATE (Gemini, CodeRabbit, local agents) Major fixes: - delete() now accepts author param for accurate RETRACT audit trail (Gemini, Copilot, CodeRabbit) - Add author_seniority, author_is_human, category to operation log schema (Gemini, CodeRabbit) - Add category field to OperationLogEntry model (CodeRabbit) - Add logging before raise in model validators and _tags_from_json (local agents) - Strict tag validation -- reject non-string/blank entries instead of filtering (CodeRabbit, local agents) - Add OrgMemoryQueryError to row-parse except tuples (Copilot) - Remove broad except Exception in hybrid_backend (local agents) - Fix delete() docstring (local agents) - Add SQL comments on time-travel CTE query (local agents) - Add composite index on operation log (timestamp, fact_id) (local agents) - Update CLAUDE.md with all 19 org_memory event constants (local agents) - Fix bare assert in test_hybrid_backend (local agents) - Assert tuple directly in tag tests (CodeRabbit)
- Split store.py (1066 lines) into store.py (protocol, 175 lines) and sqlite_store.py (implementation, 903 lines) - Add conftest.py with shared connected_store fixture, removing 25+ try/finally blocks from test_mvcc_store.py and test_store.py - Reconcile memory-consistency.md with OrgFactStore-only MVCC rollout - Fix concurrent test: two SQLiteOrgFactStore on temp file + gather - Fix snapshot boundary test: mock datetime for deterministic timestamps - Normalize snapshot_at input timestamp to UTC before serialization
Add return type to connected_store fixture (AsyncGenerator), SQLiteOrgFactStore type to all connected_store parameters, Path type to tmp_path, and return type to _fake_now helper. Fixes mypy no-untyped-def errors in test files.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (4)
src/synthorg/memory/org/models.py (1)
272-305:⚠️ Potential issue | 🟠 Major
snapshot_at()still drops author provenance.
org_facts_snapshotstoresauthor_agent_id,author_seniority,author_is_human, andauthor_autonomy_level, butOperationLogSnapshothas nowhere to return them. That makes time-travel reads lossy compared withget(), even though the design page now documents snapshot author info. Add the author fields here, or returnOrgFactplus MVCC metadata, so historical reads preserve full fact state.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/models.py` around lines 272 - 305, OperationLogSnapshot currently omits author provenance fields saved in org_facts_snapshot, causing snapshot_at() to return lossy historical facts; update the OperationLogSnapshot model to include author_agent_id, author_seniority, author_is_human, and author_autonomy_level (with appropriate types and Field descriptions) so snapshot_at() can return full historical author metadata, or alternatively change snapshot_at() to return a tuple/structure of OrgFact plus MVCC metadata (including those four author fields) so time-travel reads preserve complete fact state (refer to the OperationLogSnapshot class and snapshot_at()/org_facts_snapshot usage to locate where to add/return these fields).src/synthorg/memory/org/sqlite_store.py (3)
50-65:⚠️ Potential issue | 🟠 MajorTime-travel still cannot reproduce the stored
created_at.
save()persistsfact.created_atintoorg_facts_snapshot.created_at, but the append-only log never records that value.snapshot_at()therefore reconstructscreated_atfromMIN(timestamp), so any backfilled/imported fact with an explicit creation time will disagree betweenget()andsnapshot_at()for the same version. Persist the fact creation timestamp in the log and replay from that column instead of operation time.Also applies to: 510-550, 853-857
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` around lines 50 - 65, The operation log schema and replay use operation timestamp instead of the fact's creation time, causing created_at mismatches between save()/get() and snapshot_at(); update the org_facts_operation_log schema to add a created_at TEXT column, modify the code path that appends to the log (the save() logic that inserts into org_facts_operation_log) to persist fact.created_at into this new column, and change snapshot_at() to reconstruct created_at from MIN(created_at) (and any replay logic that derives created_at) rather than MIN(timestamp) so backfilled/imported facts retain their original creation time.
208-208:⚠️ Potential issue | 🟠 MajorSwitch these handlers to the repo’s mandated multi-
exceptform.This file still uses tuple-style
except (...) as exc, which does not match the project’s Python 3.14 rule and is likely to keep ruff failing. Convert the multi-except handlers here to the required comma-separated syntax everywhere in this module.As per coding guidelines, "
**/*.py: Use PEP 758 except syntax:except A, B:(no parentheses)—ruff enforces this on Python 3.14."Also applies to: 255-255, 296-296, 346-350, 385-385, 631-635
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` at line 208, Replace tuple-style exception handlers in this module (e.g. "except (KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc") with the repo-mandated PEP 758 comma-separated form ("except KeyError, ValueError, ValidationError, OrgMemoryQueryError as exc"); update every similar occurrence listed in the review (the groups at the shown ranges) so they use the new syntax and keep the same exception variable name (exc) and handler body unchanged.
494-564:⚠️ Potential issue | 🟠 MajorRollback these write transactions on cancellation too.
Both methods open
BEGIN IMMEDIATE, butCancelledErrorbypasses the current handlers. If a task is cancelled afterBEGINand beforeCOMMIT/ROLLBACK, the shared connection is left inside an open transaction and later calls can fail against poisoned state. Add an explicitexcept asyncio.CancelledError:in both methods that rolls back and re-raises.Also applies to: 595-644
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/synthorg/memory/org/sqlite_store.py` around lines 494 - 564, The transaction-start block that calls await db.execute("BEGIN IMMEDIATE") inside the async with self._write_lock (the block that calls _append_to_operation_log and performs the INSERT into org_facts_snapshot) currently only catches sqlite3.Error; add an explicit except asyncio.CancelledError handler that executes a rollback on the same db (await db.execute("ROLLBACK") guarded with contextlib.suppress(sqlite3.Error) if desired) and then re-raises the CancelledError to ensure the connection is not left in an open transaction; make the same change to the other method with its own BEGIN IMMEDIATE/COMMIT/ROLLBACK sequence (the second block around lines 595-644) so both transactional paths roll back on cancellation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 688-736: The query method accepts a limit that can be negative
(SQLite treats -1 as no limit), so validate and clamp the limit at the method
boundary in query to enforce the intended 1..100 contract before building the
SQL; inside query (function name: query, table: org_facts_snapshot, param:
limit) check that limit is an int within the allowed range (e.g., if limit < 1
set to 1, if limit > 100 set to 100, or raise ValueError) and then use the
validated value when appending to params and building the LIMIT clause so an
external caller cannot bypass the cap.
In `@src/synthorg/memory/org/store.py`:
- Around line 110-115: The store.delete method signature was changed to require
the author parameter as keyword-only (async def delete(self, fact_id:
NotBlankStr, *, author: OrgFactAuthor)), which breaks callers that pass author
positionally; update all callers (e.g., the calls in composite adapter,
consolidation.service, consolidation.retention, consolidation.simple_strategy,
consolidation.dual_mode_strategy, and consolidation.llm_strategy) to call
delete(fact_id, author=some_author) instead of delete(fact_id, some_author),
ensuring the correct OrgFactAuthor value is passed as the author keyword; verify
each updated call site compiles and run tests to confirm no other positional
uses remain.
---
Duplicate comments:
In `@src/synthorg/memory/org/models.py`:
- Around line 272-305: OperationLogSnapshot currently omits author provenance
fields saved in org_facts_snapshot, causing snapshot_at() to return lossy
historical facts; update the OperationLogSnapshot model to include
author_agent_id, author_seniority, author_is_human, and author_autonomy_level
(with appropriate types and Field descriptions) so snapshot_at() can return full
historical author metadata, or alternatively change snapshot_at() to return a
tuple/structure of OrgFact plus MVCC metadata (including those four author
fields) so time-travel reads preserve complete fact state (refer to the
OperationLogSnapshot class and snapshot_at()/org_facts_snapshot usage to locate
where to add/return these fields).
In `@src/synthorg/memory/org/sqlite_store.py`:
- Around line 50-65: The operation log schema and replay use operation timestamp
instead of the fact's creation time, causing created_at mismatches between
save()/get() and snapshot_at(); update the org_facts_operation_log schema to add
a created_at TEXT column, modify the code path that appends to the log (the
save() logic that inserts into org_facts_operation_log) to persist
fact.created_at into this new column, and change snapshot_at() to reconstruct
created_at from MIN(created_at) (and any replay logic that derives created_at)
rather than MIN(timestamp) so backfilled/imported facts retain their original
creation time.
- Line 208: Replace tuple-style exception handlers in this module (e.g. "except
(KeyError, ValueError, ValidationError, OrgMemoryQueryError) as exc") with the
repo-mandated PEP 758 comma-separated form ("except KeyError, ValueError,
ValidationError, OrgMemoryQueryError as exc"); update every similar occurrence
listed in the review (the groups at the shown ranges) so they use the new syntax
and keep the same exception variable name (exc) and handler body unchanged.
- Around line 494-564: The transaction-start block that calls await
db.execute("BEGIN IMMEDIATE") inside the async with self._write_lock (the block
that calls _append_to_operation_log and performs the INSERT into
org_facts_snapshot) currently only catches sqlite3.Error; add an explicit except
asyncio.CancelledError handler that executes a rollback on the same db (await
db.execute("ROLLBACK") guarded with contextlib.suppress(sqlite3.Error) if
desired) and then re-raises the CancelledError to ensure the connection is not
left in an open transaction; make the same change to the other method with its
own BEGIN IMMEDIATE/COMMIT/ROLLBACK sequence (the second block around lines
595-644) so both transactional paths roll back on cancellation.
🪄 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: 894269fc-af48-4534-a377-a236baec4b5b
📒 Files selected for processing (14)
CLAUDE.mddocs/design/memory-consistency.mdsrc/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_mvcc_store.pytests/unit/memory/org/test_store.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). (3)
- GitHub Check: Test (Python 3.14)
- GitHub Check: Build Web
- GitHub Check: Build Backend
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
No
from __future__ import annotations—Python 3.14 has PEP 649Use PEP 758 except syntax:
except A, B:(no parentheses)—ruff enforces this on Python 3.14Type hints: all public functions, mypy strict mode
Docstrings: Google style, required on public classes/functions (enforced by ruff D rules)
Immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections, use
copy.deepcopy()at construction andMappingProxyTypewrappingConfig vs runtime state: use frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state
Models: Pydantic v2 using
BaseModel,model_validator,computed_field,ConfigDict. Useallow_inf_nan=Falsein allConfigDictdeclarationsUse
NotBlankStr(fromcore.types) for all identifier/name fields instead of manual whitespace validatorsAsync concurrency: prefer
asyncio.TaskGroupfor fan-out/fan-in parallel operations in new codeLine length: 88 characters (ruff)
Functions: < 50 lines, files < 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)
Always use
loggeras the variable name (not_logger, notlog)Use event name constants from
synthorg.observability.eventsdomain modules instead of string literalsAlways use structured kwargs for logging:
logger.info(EVENT, key=value)instead oflogger.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 logging for object creation, internal flow, entry/exit of key functions
For tasks that must block indefinitely until cancelled, use
asyncio.Event().wait()instead ofasyncio.sleep(large_number)Pre-commit hooks: ruff check+format for Python files
Files:
src/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Every module with business logic MUST have:
from synthorg.observability import get_loggerthenlogger = get_logger(__name__)Vendor-agnostic everywhere: NEVER use real vendor names in project-owned code, docstrings, comments, tests, or config examples. Use generic names:
example-provider,example-large-001,example-medium-001,example-small-001,large/medium/small
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
src/synthorg/**/!(setup|sinks|syslog_handler|http_handler).py
📄 CodeRabbit inference engine (CLAUDE.md)
Never use
import logging/logging.getLogger()/print()in application code (exception: observability handler modules)
Files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
src/**/*.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/org/hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Markers:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e,@pytest.mark.slowPrefer
@pytest.mark.parametrizefor testing similar casesTests must use
test-provider,test-small-001instead of real vendor namesProperty-based testing: use Hypothesis (
@given+@settings) with profiles configured intests/conftest.pyWhen Hypothesis finds a failure, fix the underlying bug and add an
@example(...)decorator to permanently cover the case in CINEVER skip, dismiss, or ignore flaky tests—always fix them fully and fundamentally
For timing-sensitive tests, mock
time.monotonic()andasyncio.sleep()to make them deterministic
Files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.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/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pytests/unit/memory/org/test_models.pytests/unit/memory/org/test_store.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.py
🧠 Learnings (72)
📓 Common learnings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: When implementation deviates from the design spec, alert the user and explain why before proceeding
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
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-08T15:04:25.180Z
Learning: At every phase of planning and implementation, actively look for ways to improve the design and surface improvements as suggestions
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
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-08T15:04:25.180Z
Learning: Coverage: 80% minimum (enforced in CI)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Async tests: `asyncio_mode = 'auto'` in pytest—no manual `pytest.mark.asyncio` needed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Timeout: 30 seconds per test (global in `pyproject.toml`)—non-default overrides like `timeout(60)` are allowed
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: ALWAYS include `-n 8` when running pytest locally, never run tests sequentially
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Git commits: `<type>: <description>`—types: feat, fix, refactor, docs, test, chore, perf, ci (enforced by commitizen)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
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-08T15:04:25.180Z
Learning: Branches: `<type>/<slug>` from main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Pre-push hooks: mypy type-check (affected modules only) and pytest unit tests (affected modules only)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Use `gh issue list` via Bash for GitHub issue queries—MCP `list_issues` has unreliable field data
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Merge strategy: squash merge—PR body becomes the squash commit message on main
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: PR issue references: preserve existing `Closes `#NNN`` references—never remove unless explicitly asked
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: After finishing an issue implementation: create a feature branch (`<type>/<slug>`), commit, and push—do NOT create a PR automatically
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Do NOT leave work uncommitted on main—branch, commit, push immediately after finishing
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: NEVER create a PR directly—ALWAYS use `/pre-pr-review` (blocks `gh pr create` via hookify)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Fix everything valid from review agents—never skip valid issues, suggestions, or adjacent findings
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: NEVER use `cd` in Bash commands—use absolute paths or run commands directly
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: Exception to no-cd rule: `bash -c "cd <dir> && <cmd>"` is safe (runs in child process)
Learnt from: CR
URL:
File: CLAUDE.md:undefined-undefined
Timestamp: 2026-04-08T15:04:25.180Z
Learning: NEVER use Bash to write or modify files—use the Write or Edit tools. Do not use `cat >`, `echo >`, `sed -i`, or `tee` to create/modify files
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.
Applied to files:
CLAUDE.mdsrc/synthorg/memory/org/hybrid_backend.py
📚 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: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
CLAUDE.mdsrc/synthorg/memory/org/hybrid_backend.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-04-02T12:07:44.443Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T12:07:44.443Z
Learning: Applies to src/synthorg/**/*.py : Always use structured logging: `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings
Applied to files:
CLAUDE.mdsrc/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).
Applied to files:
CLAUDE.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 : Use structured logging: always `logger.info(EVENT, key=value)` — never `logger.info("msg %s", val)`
Applied to files:
CLAUDE.md
📚 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 src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit
Applied to files:
CLAUDE.mdsrc/synthorg/memory/org/hybrid_backend.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Structured kwargs in logging: always `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising; all state transitions must log at INFO; DEBUG for object creation, internal flow, entry/exit of key functions
Applied to files:
CLAUDE.mdsrc/synthorg/memory/org/hybrid_backend.py
📚 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:
src/synthorg/memory/org/hybrid_backend.pytests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/observability/events/org_memory.pydocs/design/memory-consistency.mdtests/unit/memory/org/test_store.pytests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.pysrc/synthorg/memory/org/models.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: Applies to src/synthorg/**/*.py : Log at WARNING or ERROR with context before raising exceptions in all error paths in Python.
Applied to files:
src/synthorg/memory/org/hybrid_backend.py
📚 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/org/hybrid_backend.pytests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pydocs/design/memory-consistency.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: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).
Applied to files:
src/synthorg/memory/org/hybrid_backend.pysrc/synthorg/memory/org/sqlite_store.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Log all error paths at WARNING or ERROR with context before raising; log all state transitions at INFO; log object creation/internal flow/entry-exit at DEBUG
Applied to files:
src/synthorg/memory/org/hybrid_backend.py
📚 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/persistence/**/*.py : Persistence uses pluggable PersistenceBackend protocol. SQLite is the initial backend. Settings use SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pydocs/design/memory-consistency.mdtests/unit/memory/org/test_store.pysrc/synthorg/memory/org/sqlite_store.pysrc/synthorg/memory/org/store.py
📚 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: Persistence backend: pluggable PersistenceBackend protocol in `src/synthorg/persistence/`, SQLite initial, SettingsRepository (namespaced settings CRUD).
Applied to files:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pydocs/design/memory-consistency.mdsrc/synthorg/memory/org/sqlite_store.py
📚 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:
tests/unit/memory/org/test_factory.pytests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/__init__.pysrc/synthorg/memory/org/models.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 src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (via `model_copy(update=...)`) for runtime state that evolves
Applied to files:
tests/unit/memory/org/test_hybrid_backend.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import `from synthorg.observability import get_logger` and define `logger = get_logger(__name__)`
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to {pyproject.toml,src/synthorg/__init__.py} : Update version in `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import logger via `from synthorg.observability import get_logger` and initialize with `logger = get_logger(__name__)`
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : All state transitions must log at INFO.
Applied to files:
src/synthorg/memory/org/__init__.py
📚 Learning: 2026-04-01T12:36:58.294Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T12:36:58.294Z
Learning: Applies to src/synthorg/**/*.py : Pure data models, enums, and re-exports do NOT need logging
Applied to files:
src/synthorg/memory/org/__init__.py
📚 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/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-31T16:09:24.320Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T16:09:24.320Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: Applies to src/synthorg/**/*.py : Always use constants from domain-specific modules under `synthorg.observability.events` for event names in Python (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`).
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly from the domain module
Applied to files:
src/synthorg/observability/events/org_memory.py
📚 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: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.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 src/synthorg/**/*.py : Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-31T20:07:03.035Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T20:07:03.035Z
Learning: Applies to **/*.py : Use `NotBlankStr` (from `core.types`) for all identifier/name fields, including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants, instead of manual whitespace validators
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: Applies to **/*.py : Use `NotBlankStr` from `core.types` for all identifier/name fields in Python (including optional and tuple variants) instead of manual whitespace validators.
Applied to files:
tests/unit/memory/org/test_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`
Applied to files:
tests/unit/memory/org/test_models.pysrc/synthorg/memory/org/models.py
📚 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:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-30T10:41:40.176Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-30T10:41:40.176Z
Learning: Update the relevant `docs/design/` page to reflect new reality when approved deviations from spec occur
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: When implementation deviates from the design spec, alert the user and explain why before proceeding. Update the relevant `docs/design/` page after approved deviations.
Applied to files:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
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 the 7 design pages (index, agents, organization, communication, engine, memory, operations).
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality
Applied to files:
docs/design/memory-consistency.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/memory-consistency.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:
docs/design/memory-consistency.md
📚 Learning: 2026-03-31T14:31:11.894Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:31:11.894Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue
Applied to files:
docs/design/memory-consistency.md
📚 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 tests/**/*.py : Fix flaky tests completely and fundamentally; for timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/conftest.pytests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: Applies to tests/**/*.py : For timing-sensitive Python tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins. For tasks that must block indefinitely until cancelled, use `asyncio.Event().wait()` instead of `asyncio.sleep(large_number)`.
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally; mock `time.monotonic()` and `asyncio.sleep()` for determinism; use `asyncio.Event().wait()` for indefinite blocking instead of `asyncio.sleep(large_number)`
Applied to files:
tests/unit/memory/org/test_mvcc_store.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 tests/**/*.py : NEVER skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-02T07:18:02.381Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T07:18:02.381Z
Learning: Applies to tests/**/*.py : Never skip, dismiss, or ignore flaky tests; fix them fully and fundamentally by mocking `time.monotonic()` and `asyncio.sleep()` for determinism or using `asyncio.Event().wait()` for indefinite blocking
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-04-01T15:36:39.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T15:36:39.993Z
Learning: Applies to tests/**/*.py : Flaky tests: NEVER skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock `time.monotonic()` and `asyncio.sleep()` to make them deterministic instead of widening timing margins
Applied to files:
tests/unit/memory/org/test_mvcc_store.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-01T09:37:49.451Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T09:37:49.451Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: Applies to **/*.py : Use frozen Pydantic models for config/identity. Use separate mutable-via-copy models with `model_copy(update=...)` for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Applied to files:
src/synthorg/memory/org/models.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to **/*.py : Config vs runtime state: use 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 fields in one model.
Applied to files:
src/synthorg/memory/org/models.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
📚 Learning: 2026-04-08T15:03:47.761Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-08T15:03:47.761Z
Learning: Applies to **/*.py : Use PEP 758 except syntax: use `except A, B:` (no parentheses) in Python 3.14 code. Ruff enforces this.
Applied to files:
src/synthorg/memory/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.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/org/sqlite_store.py
🔇 Additional comments (15)
tests/unit/memory/org/conftest.py (1)
1-47: LGTM!Well-structured test fixtures module. The
connected_storefixture properly handles the async lifecycle withconnect()/disconnect(), and the shared authors and factory function reduce duplication across tests.tests/unit/memory/org/test_factory.py (1)
9-9: LGTM!Import path correctly updated to reflect the module reorganization where
SQLiteOrgFactStoremoved tosqlite_store.pywhile theOrgFactStoreprotocol remains instore.py.CLAUDE.md (1)
93-93: LGTM!Event names documentation correctly extended with the four new MVCC-related constants, properly grouped with other
ORG_MEMORY_*constants.src/synthorg/memory/org/hybrid_backend.py (1)
220-220: LGTM!Tags are correctly forwarded from the write request to the constructed
OrgFact, maintaining type compatibility (tuple[NotBlankStr, ...]on both sides).src/synthorg/memory/org/__init__.py (1)
24-34: LGTM!Module re-exports correctly updated:
OperationLogEntryandOperationLogSnapshotimported frommodels,SQLiteOrgFactStorenow fromsqlite_store, andOrgFactStoreprotocol fromstore. The__all__list is properly maintained.tests/unit/memory/org/test_hybrid_backend.py (4)
21-21: LGTM!Import path correctly updated to match the module reorganization.
167-169: LGTM!Strengthened assertions verify both type and non-emptiness of the returned fact ID.
208-223: LGTM!Good test coverage for tag persistence through the hybrid backend's write path. The test verifies tags are round-tripped correctly from
OrgFactWriteRequestthrough storage and back via query.
237-259: LGTM!Test correctly updated to reflect the new error handling behavior where non-
OrgMemoryWriteErrorexceptions propagate unwrapped rather than being wrapped.src/synthorg/observability/events/org_memory.py (1)
40-46: LGTM!Well-structured MVCC event constants following the
org_memory.mvcc.<action>naming convention. The section header with Phase 1.5/D26 reference provides good traceability to the design decision.tests/unit/memory/org/test_models.py (5)
8-20: LGTM!Imports correctly updated for new enums and MVCC models.
46-67: LGTM!Good coverage for the new
autonomy_levelfield: verifies it's accepted for agent authors and correctly rejected for human authors with a clear error message.
108-154: LGTM!Comprehensive tag validation tests covering the happy path and blank/whitespace rejection for both
OrgFactandOrgFactWriteRequest. The parametrized approach keeps the tests concise.
228-310: LGTM!Thorough
OperationLogEntryvalidation tests covering PUBLISH/RETRACT operation types, version constraints, content/operation alignment rules, and immutability.
312-365: LGTM!Good
OperationLogSnapshotvalidation coverage including active/retracted states, version constraints, and thecreated_at <= retracted_attemporal invariant.
| async def delete( | ||
| self, | ||
| fact_id: NotBlankStr, | ||
| *, | ||
| author: OrgFactAuthor, | ||
| ) -> bool: |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check the delete() method signature at lines 110-115
head -115 src/synthorg/memory/org/store.py | tail -10Repository: Aureliolo/synthorg
Length of output: 262
🏁 Script executed:
# Also get broader context around those lines
sed -n '100,125p' src/synthorg/memory/org/store.pyRepository: Aureliolo/synthorg
Length of output: 727
🏁 Script executed:
# Check the actual delete() calls in the mentioned files
echo "=== adapter.py:315-324 ===" && sed -n '315,324p' src/synthorg/memory/backends/composite/adapter.py
echo -e "\n=== service.py:170-177 ===" && sed -n '170,177p' src/synthorg/memory/consolidation/service.py
echo -e "\n=== retention.py:227-232 ===" && sed -n '227,232p' src/synthorg/memory/consolidation/retention.py
echo -e "\n=== simple_strategy.py:110-120 ===" && sed -n '110,120p' src/synthorg/memory/consolidation/simple_strategy.pyRepository: Aureliolo/synthorg
Length of output: 1529
🏁 Script executed:
# Search for all delete() method calls in the codebase to find patterns
rg "\.delete\(" -A 2 -B 1 --type py src/synthorg/memory/Repository: Aureliolo/synthorg
Length of output: 2263
This API break has multiple unported callers that will fail at runtime.
delete() now requires keyword-only author parameter, but six callers pass only 2 positional arguments: src/synthorg/memory/backends/composite/adapter.py:315-324, src/synthorg/memory/consolidation/service.py:170-177, src/synthorg/memory/consolidation/retention.py:227-232, src/synthorg/memory/consolidation/simple_strategy.py:110-120, src/synthorg/memory/consolidation/dual_mode_strategy.py, and src/synthorg/memory/consolidation/llm_strategy.py. All will raise TypeError on execution unless updated to pass author as a keyword argument.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/synthorg/memory/org/store.py` around lines 110 - 115, The store.delete
method signature was changed to require the author parameter as keyword-only
(async def delete(self, fact_id: NotBlankStr, *, author: OrgFactAuthor)), which
breaks callers that pass author positionally; update all callers (e.g., the
calls in composite adapter, consolidation.service, consolidation.retention,
consolidation.simple_strategy, consolidation.dual_mode_strategy, and
consolidation.llm_strategy) to call delete(fact_id, author=some_author) instead
of delete(fact_id, some_author), ensuring the correct OrgFactAuthor value is
passed as the author keyword; verify each updated call site compiles and run
tests to confirm no other positional uses remain.
0ebd038 to
f1c7733
Compare
Preview DeploymentURL: https://pr-1134.synthorg-pr-preview.pages.dev Built from commit |
🤖 I have created a release *beep* *boop* --- ## [0.6.5](v0.6.4...v0.6.5) (2026-04-09) ### Features * add control-plane API endpoints batch ([#1118](#1118), [#1119](#1119), [#1120](#1120), [#1121](#1121)) ([#1138](#1138)) ([af11f0a](af11f0a)) * engine intelligence v2 -- trace enrichment, compaction, versioning eval ([#1139](#1139)) ([ed57dfa](ed57dfa)), closes [#1123](#1123) [#1125](#1125) [#1113](#1113) * generalize versioning to VersionSnapshot[T] for all entity types ([#1155](#1155)) ([5f563ce](5f563ce)), closes [#1131](#1131) [#1132](#1132) [#1133](#1133) * implement auxiliary tool categories -- design, communication, analytics ([#1152](#1152)) ([b506ba4](b506ba4)) * implement multi-project support -- engine orchestration ([#242](#242)) ([#1153](#1153)) ([74f1362](74f1362)) * implement SharedKnowledgeStore append-only + MVCC consistency model (Phase 1.5) ([#1134](#1134)) ([965d3a1](965d3a1)), closes [#1130](#1130) * implement shutdown strategies and SUSPENDED task status ([#1151](#1151)) ([6a0db11](6a0db11)) * persistent cost aggregation for project-lifetime budgets ([#1173](#1173)) ([5c212c5](5c212c5)), closes [#1156](#1156) * Prometheus /metrics endpoint and OTLP exporter ([#1122](#1122)) ([#1135](#1135)) ([aaeaae9](aaeaae9)), closes [#1124](#1124) * Prometheus metrics -- daily budget %, per-agent cost, per-agent budget % ([#1154](#1154)) ([581c494](581c494)), closes [#1148](#1148) ### Bug Fixes * communication hardening -- meeting cooldown, circuit breaker backoff, debate fallback ([#1140](#1140)) ([fe82894](fe82894)), closes [#1115](#1115) [#1116](#1116) [#1117](#1117) ### CI/CD * bump wrangler from 4.80.0 to 4.81.0 in /.github in the all group ([#1144](#1144)) ([b7c0945](b7c0945)) ### Maintenance * bump python from `6869258` to `5e59aae` in /docker/backend in the all group ([#1141](#1141)) ([01e99c2](01e99c2)) * bump python from `6869258` to `5e59aae` in /docker/sandbox in the all group ([#1143](#1143)) ([ea755bd](ea755bd)) * bump python from `6869258` to `5e59aae` in /docker/web in the all group ([#1142](#1142)) ([5416dd9](5416dd9)) * bump the all group across 1 directory with 2 updates ([#1181](#1181)) ([d3d5adf](d3d5adf)) * bump the all group across 1 directory with 3 updates ([#1146](#1146)) ([c609e6c](c609e6c)) * bump the all group in /cli with 2 updates ([#1177](#1177)) ([afd9cde](afd9cde)) * bump the all group in /site with 3 updates ([#1178](#1178)) ([7cff82a](7cff82a)) * bump the all group with 2 updates ([#1180](#1180)) ([199a1a8](199a1a8)) * bump vitest from 4.1.2 to 4.1.3 in /site in the all group ([#1145](#1145)) ([a8c1194](a8c1194)) * consolidated web deps (11 packages + hono security + test fixes) ([#1150](#1150)) ([63a9390](63a9390)), closes [#1147](#1147) [#1136](#1136) [#1137](#1137) * pin Docker Python base image to 3.14.x ([#1182](#1182)) ([8ffdd86](8ffdd86)) --- 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
Replace
SQLiteOrgFactStoreinternals with append-only operation log + materialized snapshot tables (D26 -- Phase 1.5). All writes append toorg_facts_operation_log; a denormalizedorg_facts_snapshottable maintains the current committed state for fast reads.Changes
org_factstable withorg_facts_operation_log(append-only log) +org_facts_snapshot(materialized snapshot)save()appends PUBLISH to log + upserts snapshot;delete()appends RETRACT + marks snapshotretracted_atget()/query()/list_by_category()filterretracted_at IS NULL(only active facts)snapshot_at(timestamp)reconstructs point-in-time state from operation log;get_operation_log(fact_id)returns full audit trailOperationLogEntryandOperationLogSnapshotfrozen Pydantic models with validators (content-operation alignment, created/retracted ordering)autonomy_level: AutonomyLevel | Nonefield (captured in operation log for audit)tags: tuple[NotBlankStr, ...]field (metadata for cross-cutting concerns)HybridPromptRetrievalBackend.write()passes tags through to storeevents.org_memoryBEGIN IMMEDIATEin save/delete for defense-in-depthmemory-consistency.mddeployment sectionSpec deviations (user-approved)
snapshot_at()andget_operation_log()placed onOrgFactStoreprotocol (notSharedKnowledgeStore, which is the separate Mem0 cross-agent protocol)Test plan
Review coverage
Pre-reviewed by 6 agents (code-reviewer, type-design-analyzer, async-concurrency-reviewer, issue-resolution-verifier, docs-consistency, silent-failure-hunter). 7 findings addressed.
Closes #1130