-
Notifications
You must be signed in to change notification settings - Fork 17
triage: treat UI/API/CLI sibling tickets as non-duplicates #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,7 +52,7 @@ Steps 3–7 progressively populate the following fields for each issue. Refer to | |
| ```json | ||
| { | ||
| "key": "EDM-1234", | ||
| "summary": "...", | ||
| "summary": "[Backend] Checkout throws 500 on submit", | ||
| "status": "Open", | ||
| "priority": "High", | ||
| "suggestedPriority": null, | ||
|
|
@@ -61,7 +61,8 @@ Steps 3–7 progressively populate the following fields for each issue. Refer to | |
| "created": "2025-06-15T10:30:00Z", | ||
| "updated": "2026-01-20T14:00:00Z", | ||
| "labels": ["backend"], | ||
| "components": ["API"], | ||
| "components": ["Backend"], | ||
| "fixSurface": "API", | ||
| "errorType": "NullPointerException", | ||
| "errorCode": null, | ||
| "errorMessageExcerpt": "at com.example.OrderTotals.apply", | ||
|
|
@@ -90,6 +91,7 @@ Steps 3–7 progressively populate the following fields for each issue. Refer to | |
| | `priorityMismatch` | Step 3 | Object `{assigned, suggested, reason}` when assigned priority ≠ description severity; otherwise null | | ||
| | `autoFixLikelihood` | Step 3 | Integer 0–100, only when recommendation is AUTO_FIX | | ||
| | `errorType`, `errorCode`, `errorMessageExcerpt`, `affectedComponent`, `symptoms`, `environmentHint` | Step 4 | Nullable strings — error signature fields | | ||
| | `fixSurface` | Step 5 | `CLI`, `UI`, or `API` when inferable; otherwise null (see "Determine fix surface") | | ||
| | `duplicateOf` | Step 5 | Jira key of the duplicate target, or null | | ||
| | `duplicateConfidence` | Step 5 | Integer 0–100 when `duplicateOf` is set; null otherwise | | ||
| | `regressionOf` | Step 6 | Object `{key, summary, resolved, reason}` or null | | ||
|
|
@@ -107,7 +109,7 @@ For every issue, evaluate the following signals and assign a recommendation. | |
| - **Description quality** — length, presence of reproduction steps, error details, expected vs actual behavior | ||
| - **Components** — which area of the system is affected | ||
| - **Labels** — any existing categorization | ||
| - **Similar titles** — scan for issues with near-identical summaries (potential duplicates) | ||
| - **Similar titles** — scan for issues with near-identical summaries (potential duplicates, but see Step 5 — different fix surfaces such as UI vs API are not duplicates) | ||
| - **Assignee** — assigned or unassigned | ||
|
|
||
| #### Recommendation Types | ||
|
|
@@ -185,17 +187,47 @@ Populate `duplicateOf` and `duplicateConfidence` from the schema above. Before f | |
|
|
||
| 1. **Error / signature angle** — same or highly similar `errorType`, `errorCode`, or overlapping `errorMessageExcerpt` / stack location | ||
| 2. **Component + symptom angle** — same Jira component(s) and matching `symptoms` or summary phrases | ||
| 3. **Description similarity** — same root cause described (not merely similar titles) | ||
| 3. **Description similarity** — same root cause described **on the same fix surface** (not merely similar titles) | ||
|
|
||
| For each issue, pick the strongest non-self candidate. If two issues describe the **same** underlying bug, mark the **newer** (by `created` or `key`) as **DUPLICATE** with `duplicateOf` pointing to the older. | ||
| For each issue, pick the strongest non-self candidate. If two issues describe the **same** underlying bug **on the same fix surface**, mark the **newer** (by `created` or `key`) as **DUPLICATE** with `duplicateOf` pointing to the older. | ||
|
|
||
| #### UI / API / CLI fix surfaces are not duplicates | ||
|
|
||
| Many projects file **separate bugs per fix surface** when the same user-visible problem must be fixed in more than one layer (e.g. UI and API). Two tickets with **near-identical descriptions** but **different fix surfaces** are **intentional siblings**, not duplicates. | ||
|
|
||
| **Do not mark DUPLICATE** when the only strong overlap is shared symptom or description but the **fix surface differs**. Treat as distinct issues; **cluster** them (Step 7) with `"relates to"` when they clearly track the same underlying problem across layers. | ||
|
|
||
| #### Determine fix surface | ||
|
|
||
| There is no Jira Target custom field. Infer `fixSurface` as `CLI`, `UI`, or `API` using the first match below: | ||
|
|
||
| 1. **Summary prefix** — title tags at the start of the summary: | ||
| - `[CLI]` → `CLI` | ||
| - `[UI]` → `UI` | ||
| - `[Backend]` → `API` (backend/API work) | ||
| 2. **Jira component** — component names that indicate the layer: | ||
| - `*-UI` suffix (e.g. `MyApp-UI`) → `UI` | ||
| - paired backend/API component without a `-UI` suffix (e.g. `MyApp`, `Backend`) → `API` | ||
| 3. **Description cues** — when title and component are ambiguous: | ||
| - **UI**: browser, page, button, modal, screenshot, frontend repro | ||
| - **API**: endpoint, HTTP status, request/response, backend service, server-side stack trace | ||
| - **CLI**: command-line invocation, terminal output, CLI subcommand | ||
|
|
||
| Set `fixSurface` to `null` only when none of the above apply. Re-infer during Step 5 even if `/scan` left it null. | ||
|
Comment on lines
+202
to
+216
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- analyze.md relevant range ---'
sed -n '180,235p' triage/skills/analyze.md
printf '%s\n' '--- scan.md relevant range ---'
sed -n '75,110p' triage/skills/scan.md
printf '%s\n' '--- all fixSurface references ---'
rg -n -C 3 'fixSurface|same-surface|surface' triage --glob '*.md'Repository: flightctl/ai-workflows Length of output: 15406 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- component-inference references ---'
rg -n -C 4 'paired backend|backend/API|component names|fix surface|fixSurface|MyApp|Backend|components' . --glob '*.md' --glob '*.json' --glob '*.yaml' --glob '*.yml' --glob '*.ts' --glob '*.js' --glob '*.py' --glob '*.sh' | head -n 500
printf '%s\n' '--- analyze.md surrounding workflow ---'
sed -n '1,130p' triage/skills/analyze.md
sed -n '235,325p' triage/skills/analyze.md
printf '%s\n' '--- scan.md step and frontmatter ---'
sed -n '1,125p' triage/skills/scan.md
printf '%s\n' '--- candidate tests and fixtures ---'
git ls-files | rg '(^|/)(test|tests|fixtures|examples|__tests__)/|fixSurface|analyz|scan'Repository: flightctl/ai-workflows Length of output: 50380 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
def infer(summary, components, description):
if summary.startswith("[CLI]"):
return "CLI"
if summary.startswith("[UI]"):
return "UI"
if summary.startswith("[Backend]"):
return "API"
for component in components:
if component.endswith("-UI"):
return "UI"
# This is the documented API branch: no positive marker is defined.
if not component.endswith("-UI"):
return "API"
text = description.lower()
if any(word in text for word in ("browser", "page", "button", "modal",
"screenshot", "frontend repro")):
return "UI"
if any(word in text for word in ("endpoint", "http status",
"request/response", "backend service",
"server-side stack trace")):
return "API"
if any(word in text for word in ("command-line invocation",
"terminal output", "cli subcommand")):
return "CLI"
return None
cases = [
("[UI] Checkout fails", ["MyApp"], "The browser page shows an error."),
("Checkout fails", ["MyApp"], "The browser page shows an error."),
("Checkout fails", ["Backend"], "The endpoint returns an error."),
("Checkout fails", ["MyApp-UI"], "The browser page shows an error."),
("Checkout fails", [], "The browser page shows an error."),
("Checkout fails", ["MyApp"], "The endpoint returns an error."),
]
for case in cases:
print(f"{case!r} -> {infer(*case)}")
PYRepository: flightctl/ai-workflows Length of output: 594 Use positive API markers for component inference. The component branch maps every component without a Require explicit backend/API markers or an actual component-pair check. Otherwise continue to description cues and use 🤖 Prompt for AI Agents |
||
|
|
||
| | Pair | Verdict | | ||
| |------|---------| | ||
| | Same description, `fixSurface` UI vs API (e.g. `[UI]` vs `[Backend]`, or `MyApp-UI` vs `Backend`) | **Not duplicate** — cluster as related | | ||
| | Same description, same `fixSurface` and same component | Candidate duplicate — apply confidence bands below | | ||
| | Same symptom, one ticket UI-only repro and one API-only repro | **Not duplicate** even if summaries match | | ||
|
|
||
| **`duplicateConfidence`** — integer **0–100** when there is a named duplicate target, reflecting how strong the match is: | ||
|
|
||
| | Band | When to use | | ||
| |------|-------------| | ||
| | **85–100** | Same error signature and same repro path; or explicit duplicate reference in text | | ||
| | **70–84** | Strong component + symptom overlap and very similar description | | ||
| | **50–69** | Plausible duplicate; needs human confirmation | | ||
| | **85–100** | Same fix surface, same error signature and same repro path; or explicit duplicate reference in text | | ||
| | **70–84** | Same fix surface, strong component + symptom overlap and very similar description | | ||
| | **50–69** | Same fix surface, plausible duplicate; needs human confirmation | | ||
| | **Below 50** | Do not mark DUPLICATE — prefer BACKLOG or cluster with a note in `reason` | | ||
|
|
||
| Set `duplicateOf` to **null** and `duplicateConfidence` to **null** when there is no duplicate target. If you keep DUPLICATE recommendation, both `duplicateOf` and `duplicateConfidence` must be set consistently. | ||
|
|
@@ -274,8 +306,8 @@ Field details: | |
|
|
||
| #### Cluster vs Duplicate | ||
|
|
||
| - **Duplicate**: the issues describe the exact same bug — mark the newer as DUPLICATE | ||
| - **Cluster**: the issues are related but distinct — they share a theme, root cause area, or feature, but each describes a different manifestation. Cluster members keep their own recommendation (FIX_NOW, AUTO_FIX, BACKLOG, etc.); clustering does not change individual recommendations | ||
| - **Duplicate**: the issues describe the exact same bug **on the same fix surface** — mark the newer as DUPLICATE | ||
| - **Cluster**: the issues are related but distinct — they share a theme, root cause area, or feature, but each describes a different manifestation or **different fix surface** (e.g. UI vs API). Cluster members keep their own recommendation (FIX_NOW, AUTO_FIX, BACKLOG, etc.); clustering does not change individual recommendations | ||
|
|
||
| ### Step 8: Generate Key Recommendations | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,6 +81,8 @@ Use **project key** `PROJECT`. | |
|
|
||
| Assign **duplicateConfidence** (0–100) per strong candidate using bulk bands. | ||
|
|
||
| **UI / API / CLI sibling tickets:** One bug per fix surface is intentional. Candidates with near-identical text but **different fix surfaces** (e.g. `[UI]` vs `[Backend]`, `MyApp-UI` vs `Backend`, or UI vs API repro in the description) are **not duplicates** — note them as related siblings and recommend linking (`relates to`), not DUPLICATE. See "Determine fix surface" in [`analyze.md`](analyze.md) Step 5. | ||
|
|
||
|
Comment on lines
+84
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Define the fix-surface contract for This rule requires the agent to distinguish different fix surfaces, but Reuse the precedence and fallback rules from As per path instructions, instructions must be unambiguous so an AI agent can produce correct output on the first try. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| ### Step 5: Integrate and finalize | ||
|
|
||
| - If a **duplicate** is conclusive, set recommendation to **DUPLICATE** with `duplicateOf` (target key) and **duplicateConfidence**; align reason. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Apply the fix-surface gate before every duplicate angle.
The same-surface condition appears in the description rule and the exact-bug rule. Lines 188-189 still list error/signature and component-plus-symptom overlap without an explicit surface check. A UI issue and an API issue can therefore become
DUPLICATEwhen they share an error code or stack location.Require matching fix surfaces before applying any duplicate angle. If surfaces differ, keep
duplicateOfandduplicateConfidencenull and cluster the issues with"relates to".Suggested clarification
📝 Committable suggestion
🧰 Tools
🪛 LanguageTool
[style] ~196-~196: Consider using a different verb for a more formal wording.
Context: ...n the same user-visible problem must be fixed in more than one layer (e.g. UI and API...
(FIX_RESOLVE)
🤖 Prompt for AI Agents