From b77fbdddbba9805c73821b206bc0c6d6aab94e1a Mon Sep 17 00:00:00 2001 From: Oleks Date: Thu, 30 Jul 2026 19:24:13 +0300 Subject: [PATCH 1/3] Fix marker-wrapper loss and add backward-compat match (kotkan/claude-plugin-inference-arbitrage#23) Root cause: bin/filing-plan and references/issue-template.md always render the ia-candidate marker HTML-comment-wrapped. A direct issue_write probe confirmed the Gitea MCP write path preserves a literal unchanged, so the loss on oleks/claude-plugin-cluster#56 and #57 happened on the Agent(anxious:issuer-agent) relay hop: an HTML comment is invisible when its surrounding text is read as markdown, so an agent relaying "what the body should say" instead of pasting it verbatim can silently drop it. Two fixes: - bin/filing-plan: find_existing()'s marker_re() now also matches the bare, unwrapped "ia-candidate: " line (end-of-line anchored, not \b, since candidate ids contain "-" and a word-boundary check would false-match a longer id sharing a prefix) so already-filed issues like cluster#56/#57 are still recognized and not duplicate-filed. - skills/offload-audit/SKILL.md: the issuer delegation prompt now fences the rendered body in its own code block and explicitly warns that the leading marker is an invisible-by-design HTML comment, not stray syntax to clean up, instead of inlining it as bare markdown the relaying agent could read right through. references/issue-template.md documents both, and tests/filing.test.sh adds coverage for the bare-marker match plus a same-prefix-different-id non-match case. Bumps plugin.json to 0.7.1. --- .claude-plugin/plugin.json | 2 +- bin/filing-plan | 27 +++++++++++++++++++++---- references/issue-template.md | 20 ++++++++++++++++++ skills/offload-audit/SKILL.md | 38 ++++++++++++++++++++++++++++------- tests/filing.test.sh | 37 ++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 12 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 05f43a1..e384ec0 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "inference-arbitrage", - "version": "0.7.0", + "version": "0.7.1", "description": "Audits a Claude Code plugin's definitions and usage transcripts to find steps that should be a deterministic script instead of raw LLM inference, and files the well-evidenced ones as issues on the target repo.", "author": { "name": "oleks" diff --git a/bin/filing-plan b/bin/filing-plan index 73a67be..06238dd 100755 --- a/bin/filing-plan +++ b/bin/filing-plan @@ -85,10 +85,29 @@ def marker(candidate_id): def marker_re(candidate_id): - """Tolerates whitespace drift inside the comment, nothing else. The id - itself must match exactly — a fuzzy id match would let two genuinely - different candidates collapse onto one issue.""" - return re.compile(r"") + """Tolerates whitespace drift inside the comment, and tolerates the + HTML-comment wrapper (``) being absent entirely, nothing else. The + id itself must match exactly — a fuzzy id match would let two genuinely + different candidates collapse onto one issue. + + The bare form (no ``) is a backward-compatibility case, not the + contract: kotkan/claude-plugin-inference-arbitrage#23 found that issues + filed on 2026-07-29 (oleks/claude-plugin-cluster#56, #57) lost the wrapper + somewhere between `filing-plan`'s render and the Gitea write — the + template and this script always render the wrapped form (see `marker()` + below and references/issue-template.md). Matching the bare line here is + purely so a *later* audit still recognizes those already-filed issues and + doesn't duplicate-file them; it does not license filing new issues without + the wrapper. + """ + wrapped = r"" + # End-of-line anchored (not \b): candidate_id contains "/" and "-", so a + # word-boundary check would treat "…label-derivation" as a match inside + # "…label-derivation-longer" (the "n"/"-" transition IS a \b). Anchoring + # to end-of-line (re.MULTILINE) instead requires an exact id, matching + # what marker() actually renders as the line's sole content. + bare = r"^ia-candidate:\s*" + re.escape(candidate_id) + r"[ \t]*$" + return re.compile(wrapped + "|" + bare, re.MULTILINE) def find_existing(candidate_id, issues): diff --git a/references/issue-template.md b/references/issue-template.md index 62d118a..a8f50c4 100644 --- a/references/issue-template.md +++ b/references/issue-template.md @@ -38,6 +38,26 @@ edited by hand on a filed issue. Removing it from an issue causes the next audit to file a duplicate — which the spec names as the single most likely way for this plugin to become hated. +**Known failure mode (kotkan/claude-plugin-inference-arbitrage#23).** Two +issues filed on 2026-07-29 (oleks/claude-plugin-cluster#56, #57) reached Gitea +with the `` wrapper stripped — the body opened with the bare text +`ia-candidate: ` instead. `bin/filing-plan` always *renders* the wrapped +form (verified: a direct `issue_write` probe with a literal `` in the +body round-trips through the Gitea MCP write path unchanged, so the API/MCP +layer is not the cause). The loss happens on the **relay hop** — +`Agent(anxious:issuer-agent)` composing the actual Gitea call from the prompt +it's handed — because an HTML comment is, by design, invisible when the prompt +text is read as markdown; an agent relaying "what the issue should say" rather +than pasting the string byte-for-byte can drop a line it never visually saw. +That is why `skills/offload-audit/SKILL.md` §5d now fences the rendered body +in the delegation prompt instead of inlining it as bare markdown — a fenced +block reads as literal text, not as renderable markup, to the relaying agent. +`bin/filing-plan`'s `find_existing()` also now matches the bare, unwrapped +form as a backward-compatibility fallback, so issues already filed without the +wrapper (like cluster#56/#57) are still found — but that fallback exists only +to avoid duplicate-filing on *already-broken* issues, not as a second +acceptable format going forward. + ## issue-title A proposal. `issuer` may rewrite it. diff --git a/skills/offload-audit/SKILL.md b/skills/offload-audit/SKILL.md index 32b877c..5091cb5 100644 --- a/skills/offload-audit/SKILL.md +++ b/skills/offload-audit/SKILL.md @@ -261,14 +261,32 @@ rendered. **Execute the plan verbatim — do not rewrite a body, and never turn One `Agent` call per action (or one call carrying all of them): +**The body MUST be embedded inside its own fenced code block in the prompt, not +inlined as bare markdown.** kotkan/claude-plugin-inference-arbitrage#23 found +that two issues filed this way (oleks/claude-plugin-cluster#56, #57) reached +Gitea with the leading `` marker's HTML-comment +wrapper stripped. The write path itself was verified clean (a literal `` round-trips through the Gitea MCP write unchanged); the loss happens on +the relay hop, because an HTML comment is invisible when its surrounding text +is read as markdown — `issuer-agent` can only paste a line byte-for-byte if it +was actually shown one, not markdown that silently ate it. A fenced block +(` ``` `) forces the body to be read and relayed as literal text. + ```text Agent(subagent_type="anxious:issuer-agent", prompt=...) # for action == "file" "File this on . It is an inference-arbitrage audit finding. Proposed title: (yours to rewrite per your taxonomy) - Body — file VERBATIM, the first line is an idempotency marker that a later - audit searches for and MUST NOT be altered or reformatted: + Body — copy the fenced block below byte-for-byte as the issue body. Do not + retype, paraphrase, reformat, or 'clean up' it — the first line is an + idempotency marker (an HTML comment, ``) that a + later audit's marker search depends on, and it renders invisible on Gitea + by design, so you will not visually see it in the rendered issue — that is + expected, do not treat it as accidental syntax to strip: + ``` + + ``` Labels: 'token-offload' is required — create it on this repo if absent (colour #8b5cf6, 'A step paying for inference where a deterministic script would do'). Add the four-axis taxonomy labels and any milestone per your own @@ -276,12 +294,18 @@ Agent(subagent_type="anxious:issuer-agent", prompt=...) domain/agents, activity/automate. Return the issue reference in full owner/repo#num form." - # for action == "comment" +# for action == "comment" + "Add this comment to , an existing inference-arbitrage finding being - re-measured. Do not open a new issue. Post the body VERBATIM (the first line - is an idempotency marker). If the issue is closed, use your judgement about - reopening; the audit does not require it. - " + re-measured. Do not open a new issue. Copy the fenced block below + byte-for-byte as the comment body — do not retype or reformat it, the first + line is an invisible-by-design HTML-comment idempotency marker (see the + 'file' case above for why). If the issue is closed, use your judgement + about reopening; the audit does not require it. + + ``` + + ```" ``` `issuer` owns repo, final title, labels beyond `token-offload`, and milestone. diff --git a/tests/filing.test.sh b/tests/filing.test.sh index f5653bc..1eaa1e6 100755 --- a/tests/filing.test.sh +++ b/tests/filing.test.sh @@ -112,6 +112,43 @@ check "found via the comment" "$(q "$tmp/plan3.json" "d['actions'][0]['action']" check "closed state surfaced for issuer" \ "$(q "$tmp/plan3.json" "d['actions'][0]['issue_state']")" "closed" +echo "== kotkan/claude-plugin-inference-arbitrage#23: a marker that lost its" +echo " HTML-comment wrapper on write (oleks/claude-plugin-cluster#56, #57)" +echo " is still found — backward compat, not a second accepted format ==" +python3 - "$tmp/plan1.json" "$tmp/bare.json" <<'PY' +import json, sys +plan = json.load(open(sys.argv[1])) +filed = next(a for a in plan["actions"] if a["action"] == "file") +# Same body, but the first line has lost its "" wrapper — the +# exact shape observed on the live tracker. +bare_body = filed["body"].replace( + "", + "ia-candidate: fixture-plugin/skill-a/label-derivation", +) +json.dump([{"number": 56, "state": "closed", "title": filed["proposed_title"], + "body": bare_body, "comments": []}], open(sys.argv[2], "w")) +PY +plan "$tmp/bare.json" "$tmp/plan-bare.json" +check "bare marker still found, no duplicate filed" \ + "$(q "$tmp/plan-bare.json" "d['summary']['to_file']")" "0" +check "recognized as a comment on the existing issue" \ + "$(q "$tmp/plan-bare.json" "d['actions'][0]['action']")" "comment" +check "on issue 56, matching the observed failure" \ + "$(q "$tmp/plan-bare.json" "d['actions'][0]['issue_number']")" "56" + +echo "== a bare marker for a DIFFERENT id still does not false-match ==" +python3 - "$tmp/bare.json" "$tmp/bare-other.json" <<'PY' +import json, sys +issues = json.load(open(sys.argv[1])) +issues[0]["body"] = issues[0]["body"].replace( + "fixture-plugin/skill-a/label-derivation", "fixture-plugin/skill-a/label-derivation-longer", +) +json.dump(issues, open(sys.argv[2], "w")) +PY +plan "$tmp/bare-other.json" "$tmp/plan-bare-other.json" +check "different id (even as a prefix) still files fresh" \ + "$(q "$tmp/plan-bare-other.json" "d['summary']['to_file']")" "1" + echo "== real Gitea API shapes parse, and a DIFFERENT id does not false-match ==" plan tests/fixtures/gitea-issues.json "$tmp/plan4.json" check "unrelated markers -> files" "$(q "$tmp/plan4.json" "d['summary']['to_file']")" "1" -- 2.54.0 From 64d6c90284d77cb5bc7f529b9179eb84bbf7cee4 Mon Sep 17 00:00:00 2001 From: Oleks Date: Thu, 30 Jul 2026 19:24:54 +0300 Subject: [PATCH 2/3] Fix nested code-fence collision the pre-push formatter introduced The previous commit nested a triple-backtick example fence inside a triple-backtick pseudocode block; the repo's markdown auto-formatter treated the inner ``` as closing the outer block and reindented/moved the "for action == comment" case out of the Agent(...) call. Use ~~~ for the outer fence so the real triple-backtick example nests without collision. --- skills/offload-audit/SKILL.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/skills/offload-audit/SKILL.md b/skills/offload-audit/SKILL.md index 5091cb5..1440d4b 100644 --- a/skills/offload-audit/SKILL.md +++ b/skills/offload-audit/SKILL.md @@ -272,7 +272,7 @@ is read as markdown — `issuer-agent` can only paste a line byte-for-byte if it was actually shown one, not markdown that silently ate it. A fenced block (` ``` `) forces the body to be read and relayed as literal text. -```text +~~~text Agent(subagent_type="anxious:issuer-agent", prompt=...) # for action == "file" "File this on . It is an inference-arbitrage audit finding. @@ -284,7 +284,6 @@ Agent(subagent_type="anxious:issuer-agent", prompt=...) by design, so you will not visually see it in the rendered issue — that is expected, do not treat it as accidental syntax to strip: ``` - ``` Labels: 'token-offload' is required — create it on this repo if absent @@ -294,19 +293,17 @@ Agent(subagent_type="anxious:issuer-agent", prompt=...) domain/agents, activity/automate. Return the issue reference in full owner/repo#num form." -# for action == "comment" - + # for action == "comment" "Add this comment to , an existing inference-arbitrage finding being re-measured. Do not open a new issue. Copy the fenced block below byte-for-byte as the comment body — do not retype or reformat it, the first line is an invisible-by-design HTML-comment idempotency marker (see the 'file' case above for why). If the issue is closed, use your judgement about reopening; the audit does not require it. - ``` ```" -``` +~~~ `issuer` owns repo, final title, labels beyond `token-offload`, and milestone. You own the body. -- 2.54.0 From 5f5462571cb347a32bf480068b8912e28518762f Mon Sep 17 00:00:00 2001 From: Oleks Date: Thu, 30 Jul 2026 19:25:27 +0300 Subject: [PATCH 3/3] Use 4-backtick outer fence (markdownlint MD048 requires backtick, not tilde) The tilde fence from the previous commit avoided the nesting collision but violated this repo's markdownlint style (backtick-only), which the pre-push hook enforces and rejected. A 4-backtick outer fence with the real 3-backtick example nested inside satisfies both: CommonMark only closes a fence on a matching-or-longer run of the same character, and MD048 sees backticks throughout. --- skills/offload-audit/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/offload-audit/SKILL.md b/skills/offload-audit/SKILL.md index 1440d4b..633cbb7 100644 --- a/skills/offload-audit/SKILL.md +++ b/skills/offload-audit/SKILL.md @@ -272,7 +272,7 @@ is read as markdown — `issuer-agent` can only paste a line byte-for-byte if it was actually shown one, not markdown that silently ate it. A fenced block (` ``` `) forces the body to be read and relayed as literal text. -~~~text +````text Agent(subagent_type="anxious:issuer-agent", prompt=...) # for action == "file" "File this on . It is an inference-arbitrage audit finding. @@ -303,7 +303,7 @@ Agent(subagent_type="anxious:issuer-agent", prompt=...) ``` ```" -~~~ +```` `issuer` owns repo, final title, labels beyond `token-offload`, and milestone. You own the body. -- 2.54.0