Corrective Action: Sanity Write Pattern Lost After Context Compaction
Date: March 11, 2026 Category: Context Loss / Post-Compaction Regression Impact: ~8 wasted tool calls (4 failed attempts) to accomplish a 1-call operation. Token waste, user frustration, and execution delay on what should have been a trivial edit. Resolution Time: ~3 minutes of thrashing before success
Incident
What Happened
During a single session, V published an article to Sanity CMS using publish-article.ts (which internally uses @sanity/client with the website .env token, running from the apps/website/ directory as an ES module). Minutes later, after context compaction occurred, V was asked to patch the same article (change "Brian Ginsberg" to "Steve Ginsberg"). Despite having just published to Sanity successfully, V failed 4 times in sequence:
- Used the monorepo root
.envtoken (read-only) — got 403 Insufficient Permissions - Wrote a temp script to
/tmp/— module@sanity/clientnot found (wrong directory) - Ran from monorepo root — same module not found
- Copied script to
apps/website/as.js— failed becausepackage.jsonhas"type": "module"(ESM), and the script usedrequire()(CJS) - Renamed to
.cjs— finally succeeded
Timeline
| Time | Event |
|---|---|
| ~11:01 CT | Article published to Sanity via publish-article.ts (success, first try) |
| ~11:30 CT | Context compaction occurred (prior conversation compressed to summary) |
| ~11:45 CT | User asked to change name in article |
| ~11:48 CT | First attempt: wrong token (root .env) — 403 |
| ~11:49 CT | Second attempt: script in /tmp/ — module not found |
| ~11:50 CT | Third attempt: still in wrong CWD — module not found |
| ~11:51 CT | Fourth attempt: .js in ESM package — require() not defined |
| ~11:52 CT | Fifth attempt: .cjs extension — success |
Root Cause
Context compaction destroyed operational knowledge that had been demonstrated minutes earlier.
The summary generated during compaction captured what was accomplished ("published article to Sanity") but not how it was accomplished. Specifically, these four critical details were lost:
- Token selection: The website
.envhas the write-capableSANITY_API_TOKEN. The monorepo root.envhas a read-only token. The publish script usesdotenvxwhich auto-loads fromapps/website/.env. - Working directory:
@sanity/clientresolves fromapps/website/node_modules/, not from the monorepo root or/tmp/. - Module system:
apps/website/package.jsondeclares"type": "module". Any.jsfile in that directory tree is treated as ESM. CJS requires the.cjsextension. - Existing tooling: The
scripts/sanity/query.jstool handles reads. For writes, thewriteClientinapps/website/src/lib/sanity/client.tsis the established pattern. An ad-hoc script was the wrong approach entirely.
Category: Context Loss / Post-Compaction Regression
This is a systemic issue, not a one-time mistake. Every context compaction discards operational "how-to" knowledge. The compaction summary format prioritizes what happened (good for continuing a conversation) but not how to do it again (needed when the same tool must be used again in the same session).
The deeper failure: V did not consult any reference material before attempting the operation. The Sanity write pattern is documented in:
memory/MEMORY.md→ Build Notes → "Sanity write client requires SANITY_API_TOKEN env var"- Dewey index → 630 (Sanity CLI), 113 (Sanity client)
apps/website/src/lib/sanity/client.ts(the actual write client)
V treated this as a "I'll just write a quick script" problem instead of checking how the system already handles Sanity writes.
Fix Applied
Immediate Resolution
Renamed the patch script from .js to .cjs, ran from apps/website/ directory using the website .env token. Article patched successfully (4 spans modified, rev r3xPnhMhowrbQmj0TOotDJ).
What Should Have Happened
One command. No temp scripts. No trial and error:
cd apps/website && SANITY_API_TOKEN=$(grep SANITY_API_TOKEN .env | tr -d '\r' | cut -d= -f2) node -e '...'
Or better: use npx tsx (already available in the website) to run a quick ESM script that imports the existing writeClient from src/lib/sanity/client.ts.
Or best: a permanent scripts/sanity/patch.js tool that handles document mutations the way scripts/sanity/query.js handles reads.
Verification
Article at valuefirstteam.com/media/articles/ten-minutes-to-a-register confirmed to show "Steve Ginsberg" throughout.
Prevention Measures
1. MEMORY.md Critical Lesson
Add to Critical Lessons:
Sanity writes require the website
.envtoken, theapps/website/working directory, and.cjsextension (or tsx) for scripts. The root.envtoken is read-only.@sanity/clientonly resolves fromapps/website/node_modules/. The package uses ESM ("type": "module"), so CJS scripts need.cjsextension. Before writing ANY ad-hoc Sanity mutation, checkscripts/sanity/query.jsfor the established pattern andapps/website/src/lib/sanity/client.tsfor the write client. Fixed Mar 11 after 4 failed attempts to patch an article that was published successfully minutes earlier in the same session.
2. Self-Correction Trigger
Add to vf-self-correction.md Infrastructure Triggers:
| Writing an ad-hoc script to mutate Sanity data without checking existing tooling | Reinventing the wheel. Check
scripts/sanity/query.js(reads) andapps/website/src/lib/sanity/client.ts(writes) first. Run fromapps/website/with the website.envtoken. Never use the root.envfor Sanity writes. |
3. Permanent Sanity Patch Tool
Create scripts/sanity/patch.js — a companion to query.js that handles document mutations. This eliminates the need for ad-hoc scripts entirely. Pattern: node scripts/sanity/patch.js <documentId> <jsonPatchOps>.
4. Post-Compaction Checklist
When resuming after context compaction, before attempting any tool/API operation that was performed earlier in the session: read the relevant Dewey index section and check for existing tooling. Do not rely on compaction summaries for operational how-to knowledge. They capture outcomes, not procedures.
Lessons
Context compaction summaries are conversation continuity tools, not operational playbooks. When a session crosses a compaction boundary and needs to repeat an operation, the correct response is to consult the system's documented patterns (Dewey index, memory files, existing scripts) rather than attempting to reconstruct the approach from memory. The 4-failure sequence here was not a knowledge gap — it was a process gap. V knew Sanity writes were possible (had just done one) but didn't pause to look up how the system does them.
The broader principle: when you know something works but don't remember how, look it up. Don't guess. The Dewey index, memory files, and codebase exist specifically so that operational knowledge survives context loss. Use them.
Related Incidents
| Date | Incident | Pattern |
|---|---|---|
| Mar 4 | NEVER use curl to query Sanity |
Same root: ad-hoc approach instead of using established scripts/sanity/query.js |
| Mar 8 | CRLF token infrastructure | Token selection confusion (which .env has which token) |
| Mar 4 | esbuild em dash / block comment bug | Module system confusion (CJS vs ESM in the website package) |