fix(store): preserve UTF-8 truncation boundaries - #809
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe store now applies shared, redaction-aware UTF-8-safe truncation to observations and prompts. MCP write tools return byte-based truncation metadata and warnings. Tests cover persistence paths, multibyte content, and redacted content. ChangesContent truncation and reporting
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Full details: Linked Issues checkExplanation The PR fixes UTF-8 boundary corruption across the three storage truncation paths and adds regression tests [ Resolution Add prompt-path truncation signaling and emit the warning from mem_save_prompt. Also align the cap, reported counts, warning text, and documentation on one unit, or update the linked issue scope if those requirements are intentionally deferred.
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Alan-TheGentleman
left a comment
There was a problem hiding this comment.
Requesting changes. mem_save_prompt still truncates silently, and its documented character limit is implemented in bytes. Expose post-redaction truncation metadata and provide warning parity for callers. Add unit coverage for the unit contract and truncation behavior before treating #697 as closed.
Alan-TheGentleman
left a comment
There was a problem hiding this comment.
The requested prompt warning, post-redaction byte metadata, and regression coverage are present. The exact correction passed RDD, full local tests, real MCP process validation, and all required CI checks. Approved for merge.
afe7011
into
Gentleman-Programming:main
…le-guard Current main already landed the observation title/content admission sentinels (ErrObservationTitleRequired, ErrObservationContentRequired), their HTTP 400 mapping and UTF-8-safe content preparation. This merge keeps all of that and reduces this branch to the part main does not cover: rejecting a titleless write before it produces a side effect. Conflict resolutions: - internal/store/store.go, AddObservation: kept main's prepareStoredContent (UTF-8 truncation boundaries, Gentleman-Programming#809) and the content guard; the branch's inline truncation and duplicate title check were dropped in favour of ValidateObservationTitle. - internal/store/store.go, UpdateObservation: kept main's pre-transaction admission and removed the branch's duplicate in-transaction title check, so a rejected update still opens no transaction. - internal/server/server.go, both handlers: kept main's switch mapping title and content errors to 400, and kept this branch's reordering so POST /observations validates the title before the session lookup. - internal/store/diagnostic.go: dropped the branch's second ErrObservationTitleRequired declaration, which collided with main's sentinel. ValidateObservationTitle now lives beside the write paths in store.go, and ValidateSyncMutationPayload keeps main's require("title") because its field() accessor already trims. Behaviour kept from this branch: engram save and mem_save reject a titleless write before opening the store or creating a session, and the HTTP create path validates the title before the session lookup so a bad session or project can no longer mask the documented 400.
🔗 Linked Issue
Closes #697
🏷️ PR Type
type:bug— Bug fixtype:feature— New featuretype:docs— Documentation onlytype:refactor— Code refactoring (no behavior change)type:chore— Maintenance, dependencies, toolingtype:breaking-change— Breaking change📝 Summary
📂 Changes
internal/store/store.gointernal/store/store_test.go🧪 Test Plan
go test ./internal/store -run 'Test(TruncateContentPreservesUTF8BytePrefix|PersistenceRoutesTruncateContentAtUTF8Boundary)$'go test ./internal/store(Windows SQLite TempDir cleanup locks remain inTestMigrate_IdempotentandTestNewErrorBranches; new tests pass)git diff --checkpasses🤖 Automated Checks
These run automatically and all must pass before merge:
Closes #N/Fixes #N/Resolves #Nstatus:approvedlabeltype:*labelgo test ./...passesgo test -tags e2e ./internal/server/...passes✅ Contributor Checklist
Closes #697)type:*label to this PRgo test ./...go test -tags e2e ./internal/server/...Co-Authored-Bytrailers in commits💬 Notes for Reviewers
The correction intentionally preserves the existing byte cap instead of converting it to a rune-count cap. When the cap lands inside a rune, the prefix backs up to the rune start before appending the existing marker.
Summary by CodeRabbit
Bug Fixes
New Features
Documentation
Tests