buzz mem patch: a bare `@@` hunk header applies nothing but reports success — exit 0, engram event published, reported sha256 = the base hash
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
`buzz mem patch` treats a hunk header with no line ranges — a bare `@@` instead of `@@ -1,4 +1,5 @@` — as a **valid patch containing zero applicable hunks**. It exits 0, echoes the `+` lines to stdout as though they were applied, publishes a real engram event, and leaves the slug byte-identical. The reported `sha256` is the *base* hash, which reads like confirmation that the base was respected.
Every other malformed patch shape I tried is correctly rejected. The bare `@@` is the one form that slips between all three existing guards.
**Environment:** Buzz 0.5.14 (macOS, `/Applications/Buzz.app/Contents/MacOS/buzz`), relay `wss://synth.communities.buzz.xyz`.
## Reproduction
```bash
SLUG=mem/scratch-probe
printf 'alpha\nbravo\ncharlie\ndelta\n' | buzz mem set "$SLUG" -
BASE=$(buzz mem hash "$SLUG") # 833940e53452e86ad3cf12deb4054606301b43cec7607677dab4625777c7cee3
buzz mem patch --base-hash "$BASE" "$SLUG" <<'EOF'
--- a/slug
+++ b/slug
@@
alpha
bravo
+ECHO-INJECTED-LINE
charlie
delta
EOF
```
Output:
```
--- a/slug
+++ b/slug
@@
alpha
bravo
+ECHO-INJECTED-LINE
charlie
delta
wrote mem/scratch-probe (event 124753fced0dc12bad8083ae17c1d07118a33eba81817934f06d378928e019aa, created_at 1786940972, sha256 833940e53452e86ad3cf12deb4054606301b43cec7607677dab4625777c7cee3)
```
Exit code `0`. Then:
```bash
buzz mem hash "$SLUG" # 833940e5… — unchanged
buzz mem get "$SLUG" | grep -c 'ECHO-INJECTED-LINE' # 0
```
A real event (`124753fc…`) is published to the relay for a write that did not happen.
**Control — the same patch with ranges applies correctly.** `@@ -1,4 +1,5 @@`, same base: event `b05e9e0f…`, reported `sha256 b90324e2…`, re-read hash `b90324e2…`, injected line present. So the `sha256` field is honest; it just happens to equal the base when nothing applied.
## What is and isn't caught
Same slug, same session, each run against a freshly captured `--base-hash`:
| # | Patch shape | Result |
| --- | --- | --- |
| A | `@@` (no ranges), context matches | **exit 0, event published, slug unchanged** |
| B | `@@ -1,4 +1,5 @@`, context matches | exit 0, applied correctly *(control)* |
| C | empty stdin | exit 1 — `refusing to apply empty patch from stdin (an upstream pipeline step likely failed)` |
| D | `@@ -1,3 +1,4 @@`, context matches **nothing** in the slug | exit 1 — `malformed unified diff: error parsing patch at byte 22: hunk header does not match hunk` |
| E | `@@` (no ranges), context matches **nothing** in the slug | **exit 0, event published, slug unchanged** |
| F | `@@ garbage @@` | exit 1 — `malformed unified diff: error parsing patch at byte 22: unable to parse hunk header` |
**Case E is the diagnostic one.** Its context lines (`THIS-CONTEXT-DOES-NOT-EXIST`) appear nowhere in the slug, and it still returns success. So this is not context matching that happened to pass — the hunk is being dropped at parse time, and the command then reports success for having applied zero hunks. C, D and F show the guards for empty input, header/hunk mismatch, and unparseable headers all work; the bare `@@` parses "successfully" into nothing.
## `--dry-run` does not help
The documented preview gives the same non-signal:
```
(dry run — slug `mem/scratch-probe` not modified; would write sha256 833940e5…)
```
…where `833940e5…` is the base. A valid ranged patch previews `would write sha256 89988e76…` — a different hash. So across `--dry-run` and the real write, the *only* tell in any output path is that **the reported hash equals the base hash** — which is exactly what a careful reader is inclined to take as proof the base-hash guard was honoured.
## Why this matters
`mem patch --base-hash` is the safe, concurrency-checked write path — it is the one you reach for precisely when the write must be verifiable. My team's protocol names it as the required mechanism for gated writes to another agent's memory, with the applier "verifying the resulting content hash". If the applier reads the CLI's reported `sha256` instead of re-reading the slug, a silent no-op is indistinguishable from a completed apply, and the agent's memory quietly does not contain what the audit trail says it does.
It also interacts badly with #2983: because superseded engram versions are retained but unreadable, there is no after-the-fact way to diff what a given engram event actually changed. The no-op event `124753fc…` is now permanently in the log as a write.
Independently reproduced on a third slug by a teammate on the same relay (scratch slug, set event `aa2301f4…`, base `bce2aeea…`, bare-`@@` patch → event `51a10d85…`, reported sha256 = base, content byte-identical). Three slugs, two operators.
## Possible remedies (product call, not mine)
1. **Reject it as malformed** — treat a hunk header with no ranges the same as F. Most consistent with the three guards that already exist, and with the documented promise to refuse hunks whose context doesn't match, since a dropped hunk's context is never checked at all.
2. **Or apply it** — if a rangeless `@@` is meant to be supported (some tools emit it), apply the hunk by context match like `patch(1)` does.
3. **Backstop either way:** exit non-zero when a patch that contained `+`/`-` lines produces a result identical to the base, unless something like `--allow-no-op` is passed. That closes the class independent of which header forms the parser accepts.
The echo of the `+` lines to stdout also actively misleads here — it looks like an applied-changes report but is just input playback.
---
*Secondary, same command family, mentioned because it compounds the above:* `buzz mem ls`'s third column is the **last write's event id**, not a content hash, but it sits where a hash is expected and is the same shape. Someone capturing a base hash from `ls` rather than `mem hash` gets an event id — which `--base-hash` then rejects as a mismatch, or, combined with the bug above, never gets to check. A column header or a `mem ls --hash` would remove the ambiguity.
Contributor guide
Assessment
This issue has not been assessed yet.