Skip to content

Fix YAML storage identity collisions#251

Open
mattfaltyn wants to merge 2 commits into
MotleyAI:mainfrom
mattfaltyn:agent/fix-yaml-storage-identity-collisions
Open

Fix YAML storage identity collisions#251
mattfaltyn wants to merge 2 commits into
MotleyAI:mainfrom
mattfaltyn:agent/fix-yaml-storage-identity-collisions

Conversation

@mattfaltyn

@mattfaltyn mattfaltyn commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Store filesystem-sensitive datasource, model, and memory IDs in a reserved .encoded namespace using reversible UTF-8 hex while retaining readable paths for portable lowercase IDs.
  • Migrate legacy non-portable filenames atomically after preflighting every destination; refuse divergent raw/encoded duplicates without deleting either copy.
  • Require exact spelling for legacy-path fallback so case-insensitive filesystems cannot resolve x to an existing X file.
  • Add YAML/SQLite parity coverage for X and x, legacy migration regressions, and storage-layout documentation.

Closes #249

Validation

  • .venv/bin/ruff check slayer/ tests/
  • .venv/bin/pytest tests/ -m "not integration" --timeout=120 -q — 6,501 passed, 4 skipped, 3 xfailed
  • .venv/bin/pytest tests/ -m "integration" --timeout=900 -q — passed with expected environment-specific skips and xfail

Summary by CodeRabbit

  • Bug Fixes
    • Preserved distinct model, datasource, and memory identifiers that differ by case or Unicode normalization.
    • Prevented identifier aliasing on case-insensitive/normalizing filesystems by using a filesystem-safe encoded layout.
    • Added conflict-aware, idempotent migrations with safe relocation and conflict detection.
  • Documentation
    • Expanded storage documentation with the encoded/non-encoded directory rules and the per-memory Markdown + YAML frontmatter format.
  • Tests
    • Added async coverage for case-sensitive ids, correct encoded-path behavior, migration round-trips, and failure when “raw” and “encoded” contents conflict.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

YAMLStorage now uses reversible encoded filesystem paths for non-portable identifiers, migrates legacy identity files, and updates model, datasource, and memory CRUD operations to preserve case-sensitive IDs. Documentation and regression tests describe the layouts and migration behavior.

Changes

YAML identity storage

Layer / File(s) Summary
Encoded path policy and migration
slayer/storage/yaml_storage.py, docs/configuration/storage.md
Shared helpers classify identifiers, encode non-portable names, validate duplicate targets, and migrate legacy identity files during initialization.
Model and datasource path resolution
slayer/storage/yaml_storage.py, docs/concepts/models.md, docs/configuration/datasources.md, tests/test_storage.py, tests/test_memory_string_ids.py
Model and datasource persistence resolves encoded and legacy paths across reads, writes, listings, updates, and deletions while preserving identifier casing.
Memory migration and storage paths
slayer/storage/yaml_storage.py, docs/concepts/memories.md, tests/test_yaml_memories_mdfiles.py, tests/test_memory_string_ids.py
Memory migration and CRUD operations use encoded-or-raw Markdown paths and validate distinct case-sensitive memory identifiers.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant YAMLStorage
  participant Filesystem
  participant IdentityReader
  YAMLStorage->>Filesystem: scan raw and encoded identity paths
  Filesystem-->>YAMLStorage: matching identity files
  YAMLStorage->>IdentityReader: compare duplicate file contents
  IdentityReader-->>YAMLStorage: identical or divergent result
  YAMLStorage->>Filesystem: atomically migrate legacy paths
  YAMLStorage->>Filesystem: read or write encoded identity paths
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR appears to satisfy #249 by adding reversible encoded paths, safe migration, legacy compatibility, and regression tests for X/x collisions.
Out of Scope Changes check ✅ Passed The changes stay focused on storage collision handling, related migrations, tests, and documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely and accurately summarizes the main change: fixing YAML storage identity collisions.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
slayer/storage/yaml_storage.py (3)

81-88: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant exception in the tuple. UnicodeDecodeError is a subclass of ValueError, so catching both is redundant and trips SonarCloud. except ValueError alone covers both bytes.fromhex (odd length / bad char) and .decode("utf-8") failures.

♻️ Simplify
     try:
         return bytes.fromhex(value).decode("utf-8")
-    except (UnicodeDecodeError, ValueError):
+    except ValueError:
         return None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slayer/storage/yaml_storage.py` around lines 81 - 88, In _decode_storage_id,
simplify the exception handler to catch only ValueError, preserving the existing
None return behavior for invalid hex input and UTF-8 decoding failures.

Source: Linters/SAST tools


165-226: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Cognitive complexity gate failing (26 > 15). SonarCloud flags migrate_identity_paths as a build failure. The three near-identical scan loops (datasources / models / memories) can be factored into a small helper that yields (source, target) pairs given a directory, suffix, and a target-builder, which both clears the gate and removes duplication.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slayer/storage/yaml_storage.py` around lines 165 - 226, Reduce the cognitive
complexity of migrate_identity_paths by extracting the repeated datasource,
model, and memory scanning logic into a small helper that yields source/target
pairs from a directory, suffix, and target-builder. Update
migrate_identity_paths to use this helper while preserving the existing
portable-ID checks, encoded target paths, and _move_identity_files behavior.

Sources: Linters/SAST tools, Pipeline failures


511-539: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Cognitive complexity gate failing (29 > 15). SonarCloud marks _list_all_model_identities as a build failure. Extracting the encoded-namespace scan and the raw per-datasource scan into two small helpers that each return set[tuple[str, str]] would satisfy the gate without changing behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slayer/storage/yaml_storage.py` around lines 511 - 539, The cognitive
complexity is concentrated in _list_all_model_identities. Extract the encoded
namespace traversal and raw datasource traversal into separate small helpers
returning set[tuple[str, str]], then have _list_all_model_identities handle
directory validation, invoke both helpers, combine their results, and return the
sorted identities without changing filtering or decoding behavior.

Sources: Linters/SAST tools, Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@slayer/storage/yaml_storage.py`:
- Around line 81-88: In _decode_storage_id, simplify the exception handler to
catch only ValueError, preserving the existing None return behavior for invalid
hex input and UTF-8 decoding failures.
- Around line 165-226: Reduce the cognitive complexity of migrate_identity_paths
by extracting the repeated datasource, model, and memory scanning logic into a
small helper that yields source/target pairs from a directory, suffix, and
target-builder. Update migrate_identity_paths to use this helper while
preserving the existing portable-ID checks, encoded target paths, and
_move_identity_files behavior.
- Around line 511-539: The cognitive complexity is concentrated in
_list_all_model_identities. Extract the encoded namespace traversal and raw
datasource traversal into separate small helpers returning set[tuple[str, str]],
then have _list_all_model_identities handle directory validation, invoke both
helpers, combine their results, and return the sorted identities without
changing filtering or decoding behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 87312380-16b6-485e-b8ff-f3d7beab7911

📥 Commits

Reviewing files that changed from the base of the PR and between dc2ecad and 6cf776e.

📒 Files selected for processing (8)
  • docs/concepts/memories.md
  • docs/concepts/models.md
  • docs/configuration/datasources.md
  • docs/configuration/storage.md
  • slayer/storage/yaml_storage.py
  • tests/test_memory_string_ids.py
  • tests/test_storage.py
  • tests/test_yaml_memories_mdfiles.py

@mattfaltyn
mattfaltyn marked this pull request as ready for review July 20, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

YAMLStorage silently aliases datasources, models, and memories whose IDs are filesystem-equivalent

1 participant