Emergent:Re/Patches/mcp-proposed-remove
From PickiPedia: A knowledge base of bluegrass, old time psychedelic jams, and other public domain music
A patch for pickipedia-mcp, against master @ 1a7156c (4 Nov 2026; that repo's default branch is master). Opened by magent as pickipedia-mcp#51. Full suite run here: 159 files, 2,439 tests, all passing; typecheck clean. To apply:
curl -s "https://pickipedia.xyz/index.php?title=Emergent:Re/Patches/mcp-proposed-remove&action=raw" \ | python3 -c "import sys,re;print(re.search(r'<pre>\n(.*?)
',sys.stdin.read(),re.S).group(1),end=)" \
> re.patch
git checkout -b re/proposed-remove origin/main && git am re.patch
From 8f9e67fc6e513d21f6e0c70670f90f5553cb0807 Mon Sep 17 00:00:00 2001
From: Re <re@cryptograss.live>
Date: Wed, 4 Nov 2026 22:36:55 +0000
Subject: [PATCH] A <proposed action="remove"> block goes through as written
The marking middleware keys every markup block by its bare text and hands
back the page's own copy of any block it already holds, so a bot could
neither reword nor withdraw a step it had itself proposed: the removal
marker was stripped for the lookup, the stored block came back, and the
wiki called it no change (Magenta:Tour, 4 Nov, three writes). The wiki's
gate is what judges a removal, so one now passes through untouched.
Deploy: redeploy the MCP server on maybelle after merge.
Worked on by: re, with magent and Justin, in #docs-tests-qa
---
src/middleware/verification.ts | 23 ++++++++++++++++++++++-
tests/pickipedia/marking.test.ts | 27 +++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/src/middleware/verification.ts b/src/middleware/verification.ts
index d978bbe..e054068 100644
--- a/src/middleware/verification.ts
+++ b/src/middleware/verification.ts
@@ -95,6 +95,17 @@ function stripProposalMarkers(text: string): string {
return text.replace(/\{\{(?:verified|source)\s*\|[^}]*\}\}/gi, '').trim();
}
+/**
+ * Whether a block is a proposed removal: <proposed action="remove"> round it,
+ * which the wiki's gate reads as "take these lines out once a person agrees".
+ *
+ * @param {string[]} block Lines of one markup block.
+ * @return {boolean} True if the block opens with a removal marker.
+ */
+function isProposedRemoval(block: string[]): boolean {
+ return /^<proposed\b[^>]*\baction\s*=\s*["']?remove\b/i.test(block[0].trim());
+}
+
/**
* Whether content already carries a proposal marker of either kind.
*
@@ -759,7 +770,17 @@ export function wrapProseWithBotProposes(
const key = normalizeLine(block.join(' '));
const asStored = existingBlocks?.get(key);
- if (asStored === undefined && isMarkableMarkup(block)) {
+ if (isProposedRemoval(block)) {
+ // A <proposed action="remove"> is a bot asking that this block go.
+ // Its key is the block's bare text, which is also the key of the
+ // block as the page holds it, so the restore-as-stored branch
+ // below would hand back the page's copy and the removal would
+ // vanish before the wiki saw it (re, 4 Nov: three writes to
+ // Magenta:Tour reported no_change, and a bot could neither
+ // reword nor withdraw its own pending step). The wiki's gate
+ // is what judges a removal; it goes through as written.
+ result.push(...block);
+ } else if (asStored === undefined && isMarkableMarkup(block)) {
result.push(...markMarkupBlock(block, by));
} else {
// A block already on the page goes back as the page had it.
diff --git a/tests/pickipedia/marking.test.ts b/tests/pickipedia/marking.test.ts
index 2d5c3b7..770ea03 100644
--- a/tests/pickipedia/marking.test.ts
+++ b/tests/pickipedia/marking.test.ts
@@ -281,3 +281,30 @@ describe('a redirect is never wrapped', () => {
).toBe('#REDIRECT [[Banjo (instrument)]]');
});
});
+
+describe('a proposed removal goes through as written', () => {
+ // Magenta:Tour, 4 Nov: a step the bot had proposed held a <code> tag the
+ // overlay shows literally. The bot's rewording and its withdrawal were
+ // both handed back as the page's own copy, so the wiki saw no change.
+ const page = [
+ '== Around the Mood ==',
+ '<proposed by="Re">',
+ '{{Tour step|at=search|text=Pressing <code>/</code> opens it too.|try=yes}}',
+ '</proposed>',
+ ].join('\n');
+
+ it('keeps the action="remove" wrapper instead of restoring the stored block', () => {
+ const edited = page.replace('<proposed by="Re">', '<proposed by="Re" action="remove">');
+ const out = wrapProseWithBotProposes(edited, buildLineSet(page), buildBlockSet(page));
+
+ expect(out).toContain('<proposed by="Re" action="remove">');
+ expect(out).toBe(edited);
+ });
+
+ it('still restores an unchanged pending block as the page holds it', () => {
+ const bare = page.replace('<proposed by="Re">\n', '').replace('\n</proposed>', '');
+ const out = wrapProseWithBotProposes(bare, buildLineSet(page), buildBlockSet(page));
+
+ expect(out).toBe(page);
+ });
+});
--
2.53.0