fix(memory): degrade undecodable preferences/projects to empty - #8248
fix(memory): degrade undecodable preferences/projects to empty#8248soroush5 wants to merge 1 commit into
Conversation
Opus 4.8 Review (fork) — ✅ no blocking findingsReviewed |
First Principles Review (Fable 5, fork) — 🟡 CONCERNSPremise-level review of All evidence is gathered. The base's First-Principles-Verdict: CONCERNS Title and description promise "degrade to empty"; the diff ships lossy decode and argues empty would wipe content — the code is right, the framing is stale. What this change shipsIntent: stop one bad byte in a memory file from crashing every reader, including the repair path — a FIX.
Watch
Subtractions
[FIRST-PRINCIPLES-REVIEWED] 2186415 |
Design Review (Fable 5, fork) — ✅ PASSDesign-level review of Design-Verdict: PASS Verified crash with a real deadlock (repair reads before writing), fixed at the read boundary with lossy decode that deliberately preserves the CAS baseline — sound and proportionate. Watch
Suggestions
[DESIGN-REVIEWED] 2186415 |
GPT 5.6 Review (fork) — 🔴 changes requested (blocking)Reviewed 1 of 2 blocking finding(s) are security-class and were withheld from adjudication, so the blocking verdict stands. BLOCKING -- src/kiro_crew/memory.py:325 -- Lossy decoding defeats stale-write protection BLOCKING -- src/kiro_crew/memory.py:325 -- Decode fallback adds blocking I/O on the event loop FINDING -- src/kiro_crew/memory.py:509 -- [GPT-REVIEWED] 2186415 Adjudication (Opus 4.8) — is blocking on each finding proportionate?Evidence gathered. Writing the ruling. F2 — adjudicableAnchored to F1 — fenced (annotate-only)Conditions: file must hold invalid UTF-8 (fallback only fires on [ADJUDICATION] 2186415 total=1 uphold=1 downgrade=0 [ADJUDICATION-FENCED] 2186415 fenced=1 flagged=1 🏷️ Fenced finding(s) machine-flagged as likely edge caseThe security fence keeps these findings blocking regardless of adjudication; the only clearance path is a human override recorded by a repository writer, who must independently verify a rationale before recording it — it is machine-authored, and a wrong override on a security-class finding ships exactly the class the fence exists to stop. (This lane's comment deliberately carries no override command.)
|
Open PR relationship auditThis is a consolidated, point-in-time code-level audit note. It compares complete merge-base diffs and current/merged code; it does not treat a shared topic as duplication or partial coverage as completion. Relationship findings
No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit. |
bab36d9 to
2a02bc3
Compare
|
Addressing the GPT BLOCK — reproduced it and you are right. Tracing the path: consolidation reads the baseline via Reworked to |
|
Follow-up on both CONCERNS (now 2 commits, pushed):
|
|
Noted on the relationship audit — no overlapping change on my side, nothing to coordinate. |
3eb2751 to
4e60d7d
Compare
4e60d7d to
cf2a6b8
Compare
|
Taken on the BLOCKING finding — fair catch. |
92ee28c to
2186415
Compare
|
Closing in favour of #8378, which fixes the same defect (issue #8247) at the same call sites. Both PRs make One site this PR covers and #8378 currently skips: |
|
Makes sense — I went through #8378 and it covers the same readers plus the link hardening, which mine does not have. Happy for this to land via that PR. Thanks for looking at it closely. |
Problem / Motivation
A single non-UTF-8 byte in
preferences.mdcrashes every preferences reader with a rawUnicodeDecodeError— verified:read_preferences()andadd_preference()both blow up onb"# prefs\n\xff\xfe bad bytes\n".Why it matters
Blast radius is the whole surface: the dashboard memory tab (500),
get_contextprompt assembly every turn, and — worst — the repair path itself, which reads before writing. A crash-mid-write, an editor encoding slip, or a synced file with one bad byte deadlocks the user out: the API cannot fix what the API cannot read.What changed (motivation → approach → change)
The codebase already solved this exact case in
_guarded_entry(decode fallback → warning + empty); the two small readers just never got it.read_preferencesand its identical twinread_projectsnow catchUnicodeDecodeError, log a warning, and return empty — one bad byte degrades to "no preferences" instead of killing the tab, the turn, and the repair.Tests
test_non_utf8_preferences_degrade_to_empty: corrupt file reads as empty, andadd_preferencerepairs instead of crashing (red without the fix, green with it).test_non_utf8_projects_degrade_to_empty: same for the twin.test_memory_cov80.pygreen.Manual verification
N/A — unit coverage sufficient: crash and fallback both locked by automated tests against a tmp workspace. Same environment note as before: repo session conftest errors on this machine (pre-existing), suites run with
--noconftest.Fixes #8247
Pattern harvest
Rule candidate: strict UTF-8 reads of user-editable state files need a decode fallback — one bad byte should degrade, never crash every reader including the repair path.