You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The update-jira-ticket skill exists to work around a known fragility in mcp__atlassian's create_jira_issue / update_jira_issue HTML→ADF conversion. The current skill design treats the fragility as a fact of life: agents are expected to internalize a list of composition rules, antipatterns, and character-handling constraints, then author HTML correctly on the first try. They don't, and when they don't, the recovery protocol produces collateral damage in the form of "PROBE delete me" tickets that leak into the user's backlog.
This issue isn't about the MCP tool — that's out of scope for this repo. It's about whether the skill itself can be made significantly less reliant on agent memory and significantly less prone to producing user-visible probe tickets.
Prior decisions: #467 (declined a deterministic sanitiser) and #468 (generic-logging follow-up, still open). This issue is the explicit case for re-opening #467 given accumulated evidence.
Context
Observed pattern
In a recent session, attempting to create a single Jira ticket triggered:
First attempt fails with opaque INVALID_INPUT.
Agent retries with a small change (replacing — named entities with literal em-dashes). Fails again.
Agent follows the recovery protocol, sends <p>ok</p> probe payload — succeeds, creating a real ticket titled "PROBE delete me" (now COMPPLAN-1048).
Agent bisects, identifies that <strong> wrapping <code> in the "Alternatives" bullets was the actual trigger (a composition-rule violation documented on page 2 of the skill, missed despite the agent having read the skill before attempting Build orchestration visualizer with retro game aesthetic #1).
Retry succeeds (COMPPLAN-1049).
Agent transitions the probe ticket to "Done" and records the failure in the JSONL log.
The failure modes are now well-characterized in the skill itself. The rule list in the current skill IS the sanitiser specification. The work has already been done; it just hasn't been embodied in executable form.
The HTML format isn't going away. The MCP tool's contract is HTML; the converter's quirks aren't being fixed upstream. The skill's runbook is the durable interface for the foreseeable future.
Existing constraints
Skill helpers ship via the bundleSkillHelpers pipeline: TypeScript source under packages/agents/src/<skill>/, bundled to content/skills/<skill>/<skill>.mjs. Agents invoke via node with no monorepo dependencies present at runtime.
The kb-add skill is the working precedent for a bundled helper invoked from a SKILL.md (stdin payload, JSON-on-stdout with an ok: true|false discriminant).
Proposed solution
Three coordinated changes to the skill. All three ship in one PR.
1. Pre-flight HTML validator
A bundled TypeScript helper (update-jira-ticket.mjs) the agent runs against the rendered HTML before any MCP call. It flags known-bad patterns and surfaces them as structured findings the agent can act on directly. Scope is HTML content only — the existing rules covering version_message and file-path mode stay in the skill body as one-line don't-do-this constraints (those failure classes aren't memory-pressure-dependent the way the composition rules are).
Rule classes flagged: composition violations (<code> nested with <strong>/<em>/<a>/<strike>/<u>/<sub>/<sup> in either direction), named entities outside the &/</> allowlist, <ac:*> and <ri:*> constructs, multi-line <pre>, any element outside the allowlist.
Contract: stdin = HTML payload; stdout = JSON with { ok: true } or { ok: false, findings: [...] }. Exit 0 on either; exit 1 only for invocation errors.
2. User-escalation prompt replaces silent probe
When pre-flight returns ok: true and the MCP call still fails, the agent does not create a probe ticket automatically. It surfaces the failure to the user with three explicit options: probe-and-bisect (tagged for cleanup), show the payload for manual submission, or skip creation. The bisection / retry-cap / JSONL-log machinery only runs if the user picks option 1.
3. Probe tickets carry a recognizable marker
When a probe ticket is created (option 1 above, or any legacy code path that survives), it is tagged with the Jira label mcp-probe, prefixes its description with Auto-created by recovery protocol on {YYYY-MM-DD}; safe to delete., and uses a deterministic title (mcp-probe: {YYYY-MM-DD HH:MM} bisection probe). The skill documents a JQL sweep (labels = mcp-probe AND created < -1d) so the user can clean up residual probes without archaeology.
Items #4 (active failure-log threshold nudge) and #5 (worked-example library) from the original brainstorm are out of scope. #4 overlaps with #468; #5 is gilding once the validator exists. They can be revisited if residual failures justify it.
Acceptance criteria
A bundled helper exists at packages/agents/content/skills/update-jira-ticket/update-jira-ticket.mjs, built from TypeScript source under packages/agents/src/update-jira-ticket/, and registered in bundleSkillHelpers.targets.
The helper takes HTML on stdin and emits { ok: true } or { ok: false, findings: [...] } on stdout, with exit 0 for both and exit 1 only for invocation errors.
The helper flags the five rule classes named above (composition violations, named entities, Confluence constructs, multi-line <pre>, disallowed elements), each finding identifying the rule, the offending snippet, and a suggested fix.
The skill body prescribes running the pre-flight checker before every update_jira_issue / create_jira_issue call and acting on findings before any MCP round-trip.
The skill's recovery protocol prompts the user with three explicit options (probe-and-bisect, show-payload, skip) instead of creating a probe ticket silently.
When a probe ticket is created, it carries the mcp-probe label, a deterministic title, and a description prefix marking it as auto-created and safe to delete.
The skill body documents the JQL cleanup query for residual mcp-probe tickets.
New and modified behaviour in the helper is covered by tests (unit tests for each rule class; the smoke test exercises the built .mjs).
Skill body, help text, and any documented invocation examples are updated to reflect the new pre-flight step, the new recovery protocol, and the probe-tagging contract; references to behaviour no longer present (silent probe creation) are removed.
Problem
The
update-jira-ticketskill exists to work around a known fragility inmcp__atlassian'screate_jira_issue/update_jira_issueHTML→ADF conversion. The current skill design treats the fragility as a fact of life: agents are expected to internalize a list of composition rules, antipatterns, and character-handling constraints, then author HTML correctly on the first try. They don't, and when they don't, the recovery protocol produces collateral damage in the form of "PROBE delete me" tickets that leak into the user's backlog.This issue isn't about the MCP tool — that's out of scope for this repo. It's about whether the skill itself can be made significantly less reliant on agent memory and significantly less prone to producing user-visible probe tickets.
Prior decisions: #467 (declined a deterministic sanitiser) and #468 (generic-logging follow-up, still open). This issue is the explicit case for re-opening #467 given accumulated evidence.
Context
Observed pattern
In a recent session, attempting to create a single Jira ticket triggered:
INVALID_INPUT.—named entities with literal em-dashes). Fails again.<p>ok</p>probe payload — succeeds, creating a real ticket titled "PROBE delete me" (now COMPPLAN-1048).<strong>wrapping<code>in the "Alternatives" bullets was the actual trigger (a composition-rule violation documented on page 2 of the skill, missed despite the agent having read the skill before attempting Build orchestration visualizer with retro game aesthetic #1).Why reopen #467
Existing constraints
bundleSkillHelperspipeline: TypeScript source underpackages/agents/src/<skill>/, bundled tocontent/skills/<skill>/<skill>.mjs. Agents invoke vianodewith no monorepo dependencies present at runtime.kb-addskill is the working precedent for a bundled helper invoked from a SKILL.md (stdin payload, JSON-on-stdout with anok: true|falsediscriminant).Proposed solution
Three coordinated changes to the skill. All three ship in one PR.
1. Pre-flight HTML validator
A bundled TypeScript helper (
update-jira-ticket.mjs) the agent runs against the rendered HTML before any MCP call. It flags known-bad patterns and surfaces them as structured findings the agent can act on directly. Scope is HTML content only — the existing rules coveringversion_messageand file-path mode stay in the skill body as one-line don't-do-this constraints (those failure classes aren't memory-pressure-dependent the way the composition rules are).Rule classes flagged: composition violations (
<code>nested with<strong>/<em>/<a>/<strike>/<u>/<sub>/<sup>in either direction), named entities outside the&/</>allowlist,<ac:*>and<ri:*>constructs, multi-line<pre>, any element outside the allowlist.Contract: stdin = HTML payload; stdout = JSON with
{ ok: true }or{ ok: false, findings: [...] }. Exit 0 on either; exit 1 only for invocation errors.2. User-escalation prompt replaces silent probe
When pre-flight returns
ok: trueand the MCP call still fails, the agent does not create a probe ticket automatically. It surfaces the failure to the user with three explicit options: probe-and-bisect (tagged for cleanup), show the payload for manual submission, or skip creation. The bisection / retry-cap / JSONL-log machinery only runs if the user picks option 1.3. Probe tickets carry a recognizable marker
When a probe ticket is created (option 1 above, or any legacy code path that survives), it is tagged with the Jira label
mcp-probe, prefixes its description withAuto-created by recovery protocol on {YYYY-MM-DD}; safe to delete., and uses a deterministic title (mcp-probe: {YYYY-MM-DD HH:MM} bisection probe). The skill documents a JQL sweep (labels = mcp-probe AND created < -1d) so the user can clean up residual probes without archaeology.Items #4 (active failure-log threshold nudge) and #5 (worked-example library) from the original brainstorm are out of scope. #4 overlaps with #468; #5 is gilding once the validator exists. They can be revisited if residual failures justify it.
Acceptance criteria
packages/agents/content/skills/update-jira-ticket/update-jira-ticket.mjs, built from TypeScript source underpackages/agents/src/update-jira-ticket/, and registered inbundleSkillHelpers.targets.{ ok: true }or{ ok: false, findings: [...] }on stdout, with exit 0 for both and exit 1 only for invocation errors.<pre>, disallowed elements), each finding identifying the rule, the offending snippet, and a suggested fix.update_jira_issue/create_jira_issuecall and acting on findings before any MCP round-trip.mcp-probelabel, a deterministic title, and a description prefix marking it as auto-created and safe to delete.mcp-probetickets..mjs).