Skip to content

fix(memory-sync): honest conflict count + owner-writes-only push (06d09cde) - #72

Merged
LanNguyenSi merged 2 commits into
masterfrom
task/sync-conflict-markers-echo-fix
Aug 3, 2026
Merged

fix(memory-sync): honest conflict count + owner-writes-only push (06d09cde)#72
LanNguyenSi merged 2 commits into
masterfrom
task/sync-conflict-markers-echo-fix

Conversation

@LanNguyenSi

Copy link
Copy Markdown
Owner

Zweck

Zwei Datenintegritätsdefekte im sync-Pfad von packages/agent-memory-sync, beide live am 2026-08-03 auf dem Mac mini reproduziert (korrupte machine-state-Snapshots im Hub).

Defekt A: stille conflicts=0 bei Marker-Carryover

mergeTexts Fast-Path-Zweige (local===base/remote===base) und der appendOnly-Erfolgspfad gaben conflict:false zurück, ohne zu prüfen, ob der Gewinner-Inhalt bereits Inline-Konfliktmarker aus einem früheren Pass trägt. In einem sync (Pull dann Push) schrieb ein echter Pull-Konflikt Marker in die lokale Datei und setzte eine saubere Base; der unmittelbar folgende Push sah remote===base und etikettierte den marker-tragenden lokalen Inhalt als sauberen „local wins" mit conflicts=0, committet in Hub und Base.

Fix: hasConflictMarkers() (auf den eindeutigen <<<<<<< -Opener verankert); jeder conflict:false-Rückgabepfad meldet conflict:true, wenn der Gewinner Marker trägt. Payload unverändert, Zähler ehrlich. Der genuine Einzelpass-Konflikt (baut Marker, conflict:true) bleibt unverändert.

Defekt B: Echo fremd-owneder Dateien

Kein Ownership-Konzept: eine Speiche bot beim Push eine Peer-machine-state/frictions-Datei, die sie nur gepullt hatte, als eigene Änderung an (Echo, last-writer-wins gegen den echten Owner-Push).

Fix: optionales SyncPathConfig.ownerScoped; die Push-Sammlung bietet unter einem ownerScoped-Verzeichnis nur <profile>.json an, und ein begleitender Base-Map-Filter strippt fremde ownerScoped-Keys, damit der base∪local-Merge nie eine fremde Datei besucht. Pull unverändert (Peers werden weiter empfangen). ownerScoped:true auf machine-state + frictions in allen drei Profilen; memory bleibt shared.

Review-Findings (adversarialer Reviewer, alle behoben)

  • HIGH (stiller Own-State-Verlust): der Owner-Filter machte config.profile datenintegritätskritisch, ein nicht passender Profilname hätte eine Maschine still aufhören lassen, ihren eigenen State zu publizieren. Jetzt: sichtbare Warnung (via notes-Zeile der Operation), wenn ein ownerScoped-Verzeichnis Peer-Dateien enthält, aber nicht die eigene <profile>.json; weiter tolerant (keine Exception) bei leerem Verzeichnis. CLI-Resolution unverändert (minimal).
  • MEDIUM (Marker-False-Positive): hasConflictMarkers auf den <<<<<<< -Opener verengt, setext-=======-Überschriften, ===-Divider und tiefe >>>>>>> -Blockquotes in Memory-Markdown werden nicht mehr als Konflikt geflaggt.
  • MEDIUM (Queue-Echo): gequeuete Snapshots werden beim Replay durch denselben Owner-Filter geleitet.
  • LOW: wins-Strategie-Zweige konsistent mit dem Marker-Ehrlichkeits-Invariant; irreführende Profil-Kommentare korrigiert.

Verifikation

  • Reviewer-Rot-vor-Fix (isolierte Kopie): Marker-Honesty-Revert → 4 rot inkl. Repro A; ownerFilter-Drop → 2 rot; nur-Base-Map-Bypass → 1 rot (Base-Map-Filter unabhängig nötig).
  • Volle Suite 137 pass / 0 fail (Implementer); Orchestrator-Isolationsläufe: Fix-Logik 32/32 + watch-mirror-delete-Negativkontrolle 7/7 grün. Build + typecheck sauber; Coverage 95.14/76.80/93.55 (Gate 86/65/86), nicht verschlechtert.

Rollout / Scope

ownerScoped wirkt erst nach git pull + Rebuild der Profile auf allen Maschinen; ohne Flag inert (rückwärtskompatibel). Konsumenten-Härtung (toolchain-parity soll unparsebare Peer-Snapshots warnen) ist separat als harness-Task 690fba7c gefiled.

Refs: agent-memory task 06d09cde

Lan Nguyen Si and others added 2 commits August 3, 2026 19:17
…rites-only push

Two data-integrity defects in the sync path, both reproduced live 2026-08-03:

Defect A (silent conflicts=0 on marker carryover): mergeText's fast-path
branches (local===base / remote===base) and the append-only success path
returned conflict:false without checking whether the winning payload already
carried inline conflict markers from a prior pass. In a single sync (pull then
push), a genuine pull-time conflict wrote markers to the local file and a clean
base; the immediately-following push then saw remote===base and re-labeled that
marker-carrying local content as a clean 'local wins' with conflicts=0, then
committed it to the hub and base. Fix: hasConflictMarkers() line-anchored check;
every conflict:false return that hands back a winning payload now reports
conflict:true when that payload carries markers. Payload unchanged, count honest.
The genuine single-pass conflict path (constructs markers, conflict:true) is
unchanged.

Defect B (peer-file echo / last-writer-wins): no ownership concept existed, so a
spoke re-offered a peer's machine-state/frictions file it had merely pulled as
its own 'local' change. Fix: optional SyncPathConfig.ownerScoped; the push-side
collection offers only <profile>.json under an ownerScoped directory, and a
companion base-map filter strips foreign ownerScoped keys so push's base-union-local
merge never visits a peer file this machine doesn't own. Pull is unchanged
(peers are still materialized for read). ownerScoped:true set on machine-state
and frictions in all three profiles; memory stays shared.

Tests: 19 new (repro A, repro B + owner-tolerance, 15 merge-honesty units);
full suite 128 pass / 0 fail; build + typecheck clean; watch-mirror-delete and
machine-state-syncpath negative controls unchanged and green.

Refs: agent-memory task 06d09cde

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbC4gdPEf4T1YD8LZV9GA7
…ing, precise marker detection, queue-replay owner filter)

Review of f51ff9f (agent-tasks 06d09cde) raised one HIGH + two MEDIUM + two
LOW; all fixed here (the local===remote unchanged-path LOW is consciously
accepted, its pin unchanged):

HIGH (silent own-state data loss): owner-writes-only made config.profile
load-bearing; a resolved profile that doesn't match the machine's owner
filename silently published nothing for its own machine-state/frictions. Now
collectLocalSyncFiles emits a visible warning (surfaced via the operation's
notes line) when an ownerScoped directory holds peer files but not this
machine's own <profile>.json; still tolerant (no exception) when the directory
is empty. CLI profile-resolution semantics are unchanged (minimal fix).

MEDIUM (marker false-positive): hasConflictMarkers narrowed to the unambiguous
'<<<<<<< ' opener line only, so setext '=======' headings, '===' dividers, and
deep '>>>>>>> ' blockquotes in ordinary memory Markdown are no longer flagged
as conflicts; an inherited full block still carries the opener and is detected.

MEDIUM (queue-replay echo): queued snapshots' localFiles/baseFiles are now
routed through filterOwnerScopedBaseMap on replay, so a snapshot enqueued
before this machine adopted ownerScoped can no longer echo a peer's file.

LOW: local-wins/remote-wins strategy branches upgrade conflict:false->true on a
marker-carrying winner (invariant completeness); corrected the misleading
'profile is a cosmetic label' comments in all three profiles.

Tests: 9 new/changed (own-file-drop warning + empty-dir control, 5 Markdown
exclusion units, 2 queue-replay strip tests, 2 wins-strategy honesty units);
full suite 137 pass / 0 fail; build + typecheck clean; coverage 95.14/76.80/
93.55 (not worsened).

Refs: agent-memory task 06d09cde

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbC4gdPEf4T1YD8LZV9GA7
@LanNguyenSi LanNguyenSi added review:tests-pass merge-approval gate prerequisite review:checklist-complete merge-approval gate prerequisite review:comments-resolved merge-approval gate prerequisite review:scope-matches-task merge-approval gate prerequisite review:evidence-logged merge-approval gate prerequisite labels Aug 3, 2026
@LanNguyenSi
LanNguyenSi merged commit 32fdd34 into master Aug 3, 2026
4 of 8 checks passed
@LanNguyenSi
LanNguyenSi deleted the task/sync-conflict-markers-echo-fix branch August 3, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:checklist-complete merge-approval gate prerequisite review:comments-resolved merge-approval gate prerequisite review:evidence-logged merge-approval gate prerequisite review:scope-matches-task merge-approval gate prerequisite review:tests-pass merge-approval gate prerequisite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant