You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The pact-memory update <id> --stdin CLI uses content-hash dedup on list-valued fields (entities, decisions, lessons_learned, etc.). For entities specifically, this means: passing an entity with an existing name but new notes creates a second entity row with the same name, rather than appending the new notes to the existing entity or replacing it.
Every consumer of the pact-memory CLI hits this trap until burned. The skill documentation says "list fields merge additively with content-hash dedup" but doesn't surface the same-name-different-content behavior, which is the load-bearing detail.
Concrete repro
# Initial state: memory has one entity {name: "auditor_handoff_capture_gap", notes: "...recurring failure mode..."}
$ pact-memory update 18ca924b --stdin << 'JSON'{"entities": [{"name": "auditor_handoff_capture_gap", "notes": "PROMOTED to enforcement-candidate..."}]}JSON# Expected: existing entity's notes appended OR replaced with the new content# Actual: memory now has TWO entities both named "auditor_handoff_capture_gap" with different notes
$ pact-memory get 18ca924b | jq '.entities | map(select(.name == "auditor_handoff_capture_gap")) | length'
2
Workaround (which works but is awkward)
Read full memory, dedup-by-name client-side merging notes with a separator, then update --replace on the entities field with the full deduped list:
pact-memory get <id>> /tmp/cur.json 2>/dev/null
python3 << 'PY' > /tmp/payload.jsonimport jsond = json.load(open('/tmp/cur.json')); ents = d['result'].get('entities', [])by_name, order = {}, []for e in ents: n = e.get('name') if n in by_name: ex = (by_name[n].get('notes') or '').strip() nw = (e.get('notes') or '').strip() if nw and nw not in ex: by_name[n]['notes'] = (ex + ' || ' + nw) if ex else nw else: by_name[n] = dict(e); order.append(n)print(json.dumps({'entities': [by_name[n] for n in order]}))PY
pact-memory update <id> --stdin --replace < /tmp/payload.json
This works (verified in reflectica/webapp-frontend audit cycle) but it's ~15 lines of client-side surgery for what feels like it should be a single CLI affordance.
Suggested fix
Two paths, either resolves the failure mode (lead-confirmed at issue-filing time):
Warn-on-duplicate-name + require --force to create a duplicate: default behavior errors out (or warns) when an entities update produces same-name-different-content; --force opts into the current content-hash-dedup-allows-dupes behavior. Loud-fail by default.
Auto-route same-name update to update-existing-entity semantics with implicit --replace shape on that entity's fields: default behavior treats same-name as "update this entity"; new fields replace existing fields; explicit content-hash-dedup behavior requires opt-in flag. Quiet-merge by default.
Either fix is structural — turns a silent affordance gap into a loud signal at CLI level, removing the client-side surgery workaround.
Hit twice in the reflectica audit cycle (once on auditor_handoff_capture_gap, once on 23d8673f cross-link entity) — both recovered via the same client-side dedup-and-replace surgery
Symptom
The
pact-memory update <id> --stdinCLI uses content-hash dedup on list-valued fields (entities, decisions, lessons_learned, etc.). Forentitiesspecifically, this means: passing an entity with an existingnamebut newnotescreates a second entity row with the same name, rather than appending the new notes to the existing entity or replacing it.Every consumer of the
pact-memoryCLI hits this trap until burned. The skill documentation says "list fields merge additively with content-hash dedup" but doesn't surface the same-name-different-content behavior, which is the load-bearing detail.Concrete repro
Workaround (which works but is awkward)
Read full memory, dedup-by-name client-side merging notes with a separator, then
update --replaceon the entities field with the full deduped list:This works (verified in reflectica/webapp-frontend audit cycle) but it's ~15 lines of client-side surgery for what feels like it should be a single CLI affordance.
Suggested fix
Two paths, either resolves the failure mode (lead-confirmed at issue-filing time):
Warn-on-duplicate-name + require
--forceto create a duplicate: default behavior errors out (or warns) when anentitiesupdate produces same-name-different-content;--forceopts into the current content-hash-dedup-allows-dupes behavior. Loud-fail by default.Auto-route same-name update to update-existing-entity semantics with implicit
--replaceshape on that entity's fields: default behavior treats same-name as "update this entity"; new fields replace existing fields; explicit content-hash-dedup behavior requires opt-in flag. Quiet-merge by default.Either fix is structural — turns a silent affordance gap into a loud signal at CLI level, removing the client-side surgery workaround.
Cross-references
18ca924b(webapp-frontend feat: implement Agent Teams executor backend with hook integration #158 organizational state snapshot —eos_upstream_filings_2026-05-20entity lists this as item 4 of the 4-item upstream-filing pass)auditor_handoff_capture_gap, once on23d8673fcross-link entity) — both recovered via the same client-side dedup-and-replace surgery