From 57ed13302170c7deacc147e94a63b38515828c66 Mon Sep 17 00:00:00 2001 From: Jeff Gonzalez Date: Mon, 7 Sep 2026 14:49:56 -0400 Subject: [PATCH] add says what it replaced, and the planted change proved less than it looked like MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upstream cart.md change was planted to test whether the tool would notice, and the honest sequence is that check did not catch it. Every document was unlocked, and unlocked means I cannot tell you. add revealed the change by overwriting the file, and the only reason the diff was visible is that git happened to be watching the working tree. So the mechanism is proven and the workflow is not: a document nobody has locked is a document nobody is checking, silently. Fixes the defect that exposed. add reported only "adopted" while overwriting local content that differed from what the publisher serves — and a differing copy is the only evidence that something moved while the document was unlocked. It now says so. Recorded with its own limit: add still overwrites rather than stashing, so outside a git working tree the note says something was lost without letting you see it. Also records the unowned half. Nothing decides when check runs, and every answer — a hook, CI, an agent's session start, a schedule — is outside the tool. Filed as a need with no owner rather than built, because choosing one would put a scheduler inside a fetcher and a comparator, with the falsifier that if nobody ever runs check unaided then a tool that reports only when asked reports nothing. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018UTxuSizozEA8yDitPuris --- .loom/event-log.md | 44 +++++++++++++++++++++++++++++++++++ internal/external/external.go | 15 ++++++++++++ 2 files changed, 59 insertions(+) diff --git a/.loom/event-log.md b/.loom/event-log.md index 7183ffd..19f5b8b 100644 --- a/.loom/event-log.md +++ b/.loom/event-log.md @@ -570,3 +570,47 @@ protocol this repository works under says **commit before dissolving, git is the only archive of the conversation.*** **An ignored cart has no archive**, so dissolving a notes file destroys the annotations outright. *One of the two is wrong and it is not ours to settle.* + +## 2026-09-07 — what the planted change actually proved `marmalade` + +**`cart.md` was changed upstream deliberately, without telling us, to see whether +the tool would notice.** *It did — and the sequence is worth recording, because +the obvious reading is wrong.* + +**`check` did not catch it.** *All eight documents were unlocked, and `unlocked` +means **I cannot tell you**.* **It was `add` that revealed the change, by +overwriting the file** — *and the only reason anybody saw what had changed is that +`git` happened to be watching the working tree.* + +> **So the mechanism is proven and the workflow is not.** *A conditional request +> against a lock works. **A document nobody has locked is a document nobody is +> checking**, and it stays that way silently.* + +**Decided, as a consequence:** *`add` now reports when it replaces local content +that differs from what the publisher is serving.* **It used to say only +`adopted`.** *A copy that differs is the only evidence that something moved while +the document was unlocked, and destroying it silently is how a change nobody saw +becomes a change nobody can find.* + +**Belief that could be shown wrong:** *that a note is enough.* **`add` still +overwrites** — *it does not stash the old bytes anywhere* — **and outside a git +working tree the note tells you something was lost without letting you see it.** +*If that bites, `add` needs `--dry-run` or a refusal.* + +## 2026-09-07 — the unowned half: somebody has to run it `marmalade` + +**Nothing here answers *when* `check` runs.** + +*`bedrock` says it about running systems and it is just as true of this:* +**nothing serves the truth, so the only mechanism is somebody looking.** *The tool +makes looking cheap; it does not make it happen.* + +**Recorded as a need with no owner rather than a feature**, *because the answers +are all outside the tool* — **a git hook, a CI job, an agent's session start, a +scheduled run** — *and choosing one here would put a scheduler inside a fetcher and +a comparator.* + +**Belief that could be shown wrong:** *that staying out of it is right.* **If in +practice nobody ever runs `check` unaided, a tool that only reports when asked is +a tool that reports nothing**, *and the thing we declined to build is the thing +that was needed.* diff --git a/internal/external/external.go b/internal/external/external.go index 211deba..b2500f3 100644 --- a/internal/external/external.go +++ b/internal/external/external.go @@ -6,6 +6,7 @@ package external import ( + "bytes" "errors" "fmt" "io" @@ -127,6 +128,17 @@ func Add(root, raw, override string, out io.Writer) error { if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { return err } + + // Say what is being replaced before replacing it. add overwrites the local + // copy, and a copy that differs from what the publisher is serving is the + // only evidence that anything changed while the document was unlocked — + // destroying it silently is how a change nobody saw becomes a change nobody + // can find. + replaced := "" + if old, err := os.ReadFile(dest); err == nil && !bytes.Equal(old, body) { + replaced = fmt.Sprintf("replaced %d bytes that differed — diff the working tree before committing", len(old)) + } + if err := os.WriteFile(dest, body, 0o644); err != nil { return err } @@ -142,6 +154,9 @@ func Add(root, raw, override string, out io.Writer) error { fmt.Fprintf(out, "adopted %s\n", rel) fmt.Fprintf(out, " from %s\n", resp.Request.URL) + if replaced != "" { + fmt.Fprintf(out, " NOTE %s\n", replaced) + } if etag == "" { fmt.Fprintf(out, " etag (none served — check cannot ask conditionally)\n") } else {