Filed issues (cluster#56, cluster#57) are missing the HTML-comment ia-candidate marker wrapper, breaking future dedup #23

Closed
opened 2026-07-30 17:02:35 +03:00 by issuer-agent · 2 comments

What happened. This plugin's own convention (skills/offload-audit/SKILL.md, references/issue-template.md) specifies that every filed candidate issue's body must begin with the literal line <!-- ia-candidate: <candidate_id> --> — an HTML comment, so it's invisible in rendered markdown but greppable by a later audit's marker search (bin/filing-plan's find_existing, which matches on the regex <!--\s*ia-candidate:\s*<id>\s*-->).

Reading the raw body of oleks/claude-plugin-cluster#56 and #57 (both filed by a prior cluster offload audit, run_id 2026-07-29T18:59:29Z) shows their first lines are plain text: ia-candidate: cluster/gitea-agent/sequential-issue-read-batching and ia-candidate: cluster/gitea-helpers/wiki-and-milestone-recipes — with no <!--/--> wrapper at all.

Impact. A follow-up audit's filing-plan plan --existing ... searches via find_existing's HTML-comment regex. Against the real (unwrapped) issue bodies, that regex found NO match for either candidate, so filing-plan proposed action: "file" (a brand-new issue) for both — even though both are the exact same candidates, already closed as fixed via oleks/claude-plugin-cluster#58. Only a targeted, out-of-band issue_read and manual comparison caught this before duplicate issues were filed. The full-text search_issues(q='ia-candidate: <id>') query in the same marker-search step DID still find them (because it's a plain substring search, not comment-syntax-sensitive) — that's the only reason this run didn't file duplicates blind.

Root cause (unconfirmed, worth checking). Either the body template used when #56/#57 were filed did not include the <!-- --> wrapper, or something in the Agent(anxious:issuer-agent)cluster:gitea-agent → Gitea chain stripped the HTML comment syntax on write (or on the read path used for this audit's own marker search). Worth checking both the exact body string handed to issuer-agent on 2026-07-29 and whether Gitea's issue-write API preserves literal <!-- --> in bodies.

Recommendation. Since dedup already has a working fallback (the full-text search), this did not cause an actual duplicate filing this time, but it is a latent bug: a future run relying on find_existing alone (e.g. if the full-text query's tokenization missed a hit) would silently file a duplicate. Either fix the marker regex to also match a bare (non-HTML-comment) ia-candidate: <id> line for backward compatibility with already-filed issues, or verify/fix whatever strips the comment wrapper so newly filed issues carry it correctly, or both.

Evidence. Confirmed by direct issue_read on oleks/claude-plugin-cluster#56 and #57 during this audit (run against cluster, window 2026-07-03 to 2026-07-30) — raw body opens with ia-candidate: ... and no comment syntax in either case.

<!-- ia-self-report: marker-discipline-broken-on-filed-issues --> **What happened.** This plugin's own convention (skills/offload-audit/SKILL.md, references/issue-template.md) specifies that every filed candidate issue's body must begin with the literal line `<!-- ia-candidate: <candidate_id> -->` — an HTML comment, so it's invisible in rendered markdown but greppable by a later audit's marker search (`bin/filing-plan`'s `find_existing`, which matches on the regex `<!--\s*ia-candidate:\s*<id>\s*-->`). Reading the raw body of oleks/claude-plugin-cluster#56 and #57 (both filed by a prior cluster offload audit, run_id 2026-07-29T18:59:29Z) shows their first lines are plain text: `ia-candidate: cluster/gitea-agent/sequential-issue-read-batching` and `ia-candidate: cluster/gitea-helpers/wiki-and-milestone-recipes` — with no `<!--`/`-->` wrapper at all. **Impact.** A follow-up audit's `filing-plan plan --existing ...` searches via `find_existing`'s HTML-comment regex. Against the real (unwrapped) issue bodies, that regex found NO match for either candidate, so `filing-plan` proposed `action: "file"` (a brand-new issue) for both — even though both are the exact same candidates, already closed as fixed via oleks/claude-plugin-cluster#58. Only a targeted, out-of-band `issue_read` and manual comparison caught this before duplicate issues were filed. The full-text `search_issues(q='ia-candidate: <id>')` query in the same marker-search step DID still find them (because it's a plain substring search, not comment-syntax-sensitive) — that's the only reason this run didn't file duplicates blind. **Root cause (unconfirmed, worth checking).** Either the body template used when #56/#57 were filed did not include the `<!-- -->` wrapper, or something in the `Agent(anxious:issuer-agent)` → `cluster:gitea-agent` → Gitea chain stripped the HTML comment syntax on write (or on the read path used for this audit's own marker search). Worth checking both the exact body string handed to `issuer-agent` on 2026-07-29 and whether Gitea's issue-write API preserves literal `<!-- -->` in bodies. **Recommendation.** Since dedup already has a working fallback (the full-text search), this did not cause an actual duplicate filing this time, but it is a latent bug: a future run relying on `find_existing` alone (e.g. if the full-text query's tokenization missed a hit) would silently file a duplicate. Either fix the marker regex to also match a bare (non-HTML-comment) `ia-candidate: <id>` line for backward compatibility with already-filed issues, or verify/fix whatever strips the comment wrapper so newly filed issues carry it correctly, or both. **Evidence.** Confirmed by direct `issue_read` on oleks/claude-plugin-cluster#56 and #57 during this audit (run against `cluster`, window 2026-07-03 to 2026-07-30) — raw body opens with `ia-candidate: ...` and no comment syntax in either case.
oleks added the agent-wip label 2026-07-30 19:18:18 +03:00
Owner

Investigated and fixed. PR: kotkan/claude-plugin-inference-arbitrage#27 (branch fix/issue-23-marker-wrapper, not yet merged — leaving arming/merge to the parent session per standing process).

Root cause — write path is clean, the loss is on the agent-relay hop.

The issue's own self-report already correctly identified both bin/filing-plan/references/issue-template.md as rendering the wrapped form, and flagged the write chain as the open question. I confirmed which half of that chain is at fault by testing the actual write path directly, not by reading code alone:

$ # issue_write create, body containing a literal HTML comment as first line
mcp__plugin_cluster_gitea-tools__issue_write(method="create", owner="kotkan",
  repo="claude-plugin-inference-arbitrage",
  title="throwaway: html-comment write-path probe (safe to delete/close)",
  body="<actual-test-marker>\n<!-- ia-candidate: probe/write-path-test -->\n\nLiteral HTML comment write-path test. Safe to close immediately.")
=> created issue #26

$ # read it back
mcp__plugin_cluster_gitea-tools__issue_read(owner="kotkan", repo="claude-plugin-inference-arbitrage", index=26)
=> body: "<actual-test-marker>\n<!-- ia-candidate: probe/write-path-test -->\n\n..."
   (i.e. "<actual-test-marker>\n<!-- ia-candidate: probe/write-path-test -->\n\n...")

The <!-- --> round-tripped byte-for-byte through issue_write → Gitea → issue_read. The Gitea API / gitea-mcp write path is not the cause. (Probe issue #26 closed immediately after the test.)

That leaves the only other hop in the documented chain — offload-audit → Agent(anxious:issuer-agent) → cluster:gitea-agent → Gitea. skills/offload-audit/SKILL.md §5d already told issuer-agent to file the body "VERBATIM," but inlined it as bare markdown text in the prompt. An HTML comment is invisible when read as markdown — so an agent relaying "what the issue should say," rather than mechanically pasting a string it can't actually see, can drop a line it never visually perceived. That's the most parsimonious explanation consistent with the evidence: template renders it correctly, write path preserves it correctly, and the only place left that could silently eat an invisible line is the LLM hop in between.

What I changed:

  1. bin/filing-planmarker_re()/find_existing() now also match the bare, unwrapped ia-candidate: <id> line, end-of-line anchored under re.MULTILINE (not \b, since candidate ids contain - and a word-boundary check would false-match a longer id sharing a prefix, e.g. label-derivation inside label-derivation-longer). This is backward compatibility for already-filed issues like cluster#56/#57 — not a second accepted format for new filings.
  2. skills/offload-audit/SKILL.md §5d — the issuer-agent delegation prompt now embeds the rendered body inside its own fenced code block (```` / ` ` `` nesting, since the whole call is itself inside a pseudocode fence) and explicitly tells the agent the leading marker is an invisible-by-design HTML comment it should expect not to see rendered, not stray syntax to clean up.
  3. references/issue-template.md — documents the failure mode, the probe evidence, and both fixes under "The marker is load-bearing."
  4. tests/filing.test.sh — new cases: a bare marker on the tracker is found and produces comment (not a duplicate file); a different candidate id that merely shares a prefix with a bare marker still files fresh (regression guard for the \b→end-of-line regex change).

plugin.json bumped to 0.7.1.

Test evidence:

$ bash tests/filing.test.sh
...
== kotkan/claude-plugin-inference-arbitrage#23: a marker that lost its
   HTML-comment wrapper on write (oleks/claude-plugin-cluster#56, #57)
   is still found — backward compat, not a second accepted format ==
  ok   bare marker still found, no duplicate filed = 0
  ok   recognized as a comment on the existing issue = comment
  ok   on issue 56, matching the observed failure = 56
== a bare marker for a DIFFERENT id still does not false-match ==
  ok   different id (even as a prefix) still files fresh = 1
...
$ echo $?
0

(Full run: all existing FR-6 checks still pass unchanged.)

Not closing this issue — that's the parent session's call once PR kotkan/claude-plugin-inference-arbitrage#27 merges and (if this repo tracks it) is deployed/picked up. The issue body's own diagnosis holds up; nothing about it was stale or misdiagnosed, this comment just confirms which hop was actually at fault and closes the loop with a fix.

Investigated and fixed. PR: kotkan/claude-plugin-inference-arbitrage#27 (branch `fix/issue-23-marker-wrapper`, not yet merged — leaving arming/merge to the parent session per standing process). **Root cause — write path is clean, the loss is on the agent-relay hop.** The issue's own self-report already correctly identified both `bin/filing-plan`/`references/issue-template.md` as rendering the wrapped form, and flagged the write chain as the open question. I confirmed which half of that chain is at fault by testing the actual write path directly, not by reading code alone: ``` $ # issue_write create, body containing a literal HTML comment as first line mcp__plugin_cluster_gitea-tools__issue_write(method="create", owner="kotkan", repo="claude-plugin-inference-arbitrage", title="throwaway: html-comment write-path probe (safe to delete/close)", body="<actual-test-marker>\n<!-- ia-candidate: probe/write-path-test -->\n\nLiteral HTML comment write-path test. Safe to close immediately.") => created issue #26 $ # read it back mcp__plugin_cluster_gitea-tools__issue_read(owner="kotkan", repo="claude-plugin-inference-arbitrage", index=26) => body: "<actual-test-marker>\n<!-- ia-candidate: probe/write-path-test -->\n\n..." (i.e. "<actual-test-marker>\n<!-- ia-candidate: probe/write-path-test -->\n\n...") ``` The `<!-- -->` round-tripped byte-for-byte through `issue_write` → Gitea → `issue_read`. **The Gitea API / gitea-mcp write path is not the cause.** (Probe issue #26 closed immediately after the test.) That leaves the only other hop in the documented chain — `offload-audit → Agent(anxious:issuer-agent) → cluster:gitea-agent → Gitea`. `skills/offload-audit/SKILL.md` §5d already told `issuer-agent` to file the body "VERBATIM," but inlined it as bare markdown text in the prompt. An HTML comment is *invisible when read as markdown* — so an agent relaying "what the issue should say," rather than mechanically pasting a string it can't actually see, can drop a line it never visually perceived. That's the most parsimonious explanation consistent with the evidence: template renders it correctly, write path preserves it correctly, and the only place left that could silently eat an invisible line is the LLM hop in between. **What I changed:** 1. `bin/filing-plan` — `marker_re()`/`find_existing()` now also match the bare, unwrapped `ia-candidate: <id>` line, end-of-line anchored under `re.MULTILINE` (not `\b`, since candidate ids contain `-` and a word-boundary check would false-match a longer id sharing a prefix, e.g. `label-derivation` inside `label-derivation-longer`). This is backward compatibility for already-filed issues like cluster#56/#57 — not a second accepted format for new filings. 2. `skills/offload-audit/SKILL.md` §5d — the `issuer-agent` delegation prompt now embeds the rendered body inside its own fenced code block (` ```` ` / ``` ` ``` ` `` nesting, since the whole call is itself inside a pseudocode fence) and explicitly tells the agent the leading marker is an invisible-by-design HTML comment it should expect not to see rendered, not stray syntax to clean up. 3. `references/issue-template.md` — documents the failure mode, the probe evidence, and both fixes under "The marker is load-bearing." 4. `tests/filing.test.sh` — new cases: a bare marker on the tracker is found and produces `comment` (not a duplicate `file`); a different candidate id that merely shares a prefix with a bare marker still files fresh (regression guard for the `\b`→end-of-line regex change). `plugin.json` bumped to `0.7.1`. **Test evidence:** ``` $ bash tests/filing.test.sh ... == kotkan/claude-plugin-inference-arbitrage#23: a marker that lost its HTML-comment wrapper on write (oleks/claude-plugin-cluster#56, #57) is still found — backward compat, not a second accepted format == ok bare marker still found, no duplicate filed = 0 ok recognized as a comment on the existing issue = comment ok on issue 56, matching the observed failure = 56 == a bare marker for a DIFFERENT id still does not false-match == ok different id (even as a prefix) still files fresh = 1 ... $ echo $? 0 ``` (Full run: all existing FR-6 checks still pass unchanged.) **Not closing this issue** — that's the parent session's call once PR kotkan/claude-plugin-inference-arbitrage#27 merges and (if this repo tracks it) is deployed/picked up. The issue body's own diagnosis holds up; nothing about it was stale or misdiagnosed, this comment just confirms which hop was actually at fault and closes the loop with a fix.
oleks removed the agent-wip label 2026-07-30 19:31:07 +03:00
oleks closed this issue 2026-07-30 19:54:28 +03:00
Owner

Fixed and merged via PR #27, commit 9a25402d37. Closing.

Fixed and merged via PR #27, commit 9a25402d373d13a3681d6032fe7b91d6aa990246. Closing.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kotkan/claude-plugin-inference-arbitrage#23