--- name: "issue-bar" description: "[skaile-development] The bar a ticket must clear to exist: six impact questions (user harm, money, stability, security, team drag, significant benefit), each answered with evidence. Use before filing an issue an agent found on its own (a ship follow-up, a review leftover, an audit finding), when triaging incoming issues, or when sweeping an existing backlog for tickets that can be closed. Returns KEEP / CLOSE / ASK per ticket with the evidence, and a ready-to-post close comment." version: 1.0.0 metadata: tags: - "issue-bar" - "triage" - "backlog" - "follow-ups" - "skaile-development" source: "NEW" --- # Issue bar An issue is a promise that someone will spend time on it. It earns that only when it names a **consequence**: something bad that happens to a user, to our money, to uptime, to security or to the team's ability to ship, or a **significant gain** that doing the work buys. A true observation about the code is neither. "This could be more robust", "a second check would be nice", "these two names disagree" are all true and all fail the bar. Apply the bar the same way to a ticket you are about to file and to one that already exists. ## The six questions Answer every question **YES** or **NO**. A YES needs its **evidence** in one line. Without evidence, the answer is NO. | # | Question | YES looks like | |---|----------|----------------| | 1 | **User harm.** Does a real user get a wrong result, lose data or work, get blocked, or see something broken, or have to work around it? | A user report, a prod log line, a repro, or a code path that normal use reaches | | 2 | **Money.** Does it cost us money we can estimate (infra, LLM tokens, paid API calls, support hours), or hold up revenue (a deal, a customer rollout)? | A rough figure or a named deal or customer. "Costs something" is not a figure. | | 3 | **Stability.** Will it crash, hang, wedge a session, corrupt data, crash-loop the backend, or break a deploy? | It has happened (log, incident, devlog), or you can show the trigger normal operation reaches | | 4 | **Security.** Is there an exploitable path now: authz bypass, data leaking across user or org, exposed credentials, injection? | The attack path, step by step, with the controls it gets past | | 5 | **Team drag.** Does it block or repeatedly slow the team: a red or flaky required check, a trap that already cost someone a real run? | The run, PR or devlog where it has already bitten someone. A trap that could bite later does not count. | | 6 | **Significant benefit.** Will doing it deliver a gain users or the team would notice: noticeably faster, a clearly better or delightful experience on a flow people use, a real simplification that unblocks planned work? | Speed: a measurement (latency, load time, token or query count) and the expected improvement. Experience: the named flow, how often it is used, AND the concrete change (steps removed, an error no longer shown, a task now possible). Simplification: the issue or plan it unblocks, by number or name. "Cleaner", "more consistent" or "slightly faster" is not a gain. | **Verdict:** - **KEEP**: at least one YES with evidence. Put the question number and the evidence in the issue body. - **CLOSE**: six NOs. - **ASK**: one answer hangs on a **specific** fact you cannot reach, such as prod data you cannot read, or the config of a control you cannot see. Name that fact. Being unable to prove a path does *not* exist is not enough: that is every defense-in-depth ticket, and it answers NO. Product calls are also ASK. Guessing either way is how the backlog fills up, and also how real bugs get closed. **Human reports.** A ticket is human-reported when its body carries neither an `Issue bar:` line nor a "Filed via …" agent footer, and it describes something a person saw happen. That person's account is evidence for Q1: score the question it supports YES, citing the report. It can still fail review: if main has since fixed it, or you reproduce the exact steps and it works, record that and give the verdict **ASK**, with the question for the reporter. A human report never goes straight to CLOSE: the reporter may know about harm the code cannot show you. ## Likelihood × severity A rare trigger is still a YES when the damage is **severe**: data loss, a cross-tenant leak, credential exposure, corruption you cannot recover from. A rare trigger with **mild** damage, like a retry, one error toast or one wasted request, is NO. Name the trigger and say how often it fires ("every wake", "once per deploy", "needs two admins editing the same row within 50 ms"). ## Answering NO by default These kinds of ticket answer NO on all six unless they carry specific evidence that overturns it. Recognise them by their **shape**, even when the wording sounds urgent: - **Defense in depth.** The primary control holds, and the ticket adds a second layer behind it. Q4 is YES only if you can show the primary control failing. - **Hypothetical edges.** "If X ever happens…" where nothing in normal operation produces X. - **Cleanup.** Refactors, renames, dead code, consistency, symmetry ("A validates, so B should too"), comment and docs polish. Q6 is YES only when the cleanup buys a gain you can name, such as unblocking a specific piece of planned work. - **Micro-optimisation.** A faster path nobody waits on. Q6 is YES only when the current cost is measured on a path users or jobs actually hit. - **Test gaps** on code with no known bug. A missing test is a YES only when the untested behaviour already broke in prod, or keeps breaking. - **Observability wishes.** "Log more", "add a metric". YES only when a real incident was hard to diagnose *for lack of exactly that signal*. - **Restatements.** Already covered by another open issue, already fixed on main, or already written in the PR that produced it. ## Assessing a ticket 1. Read the whole ticket: title, body and comments. For an existing issue, check whether main has already fixed it or another issue covers it: `gh issue view --comments`, `gh search issues --repo ""`, `git log origin/main --oneline -S ""`. 2. Answer the six questions against the **current** code and data, not what the ticket assumed when it was written. A ticket written before a fix landed is a NO today. 3. Give the verdict, and write the record: ``` # Verdict: KEEP | CLOSE | ASK 1 User harm: YES|NO — <evidence or "no reachable path"> 2 Money: YES|NO — <…> 3 Stability: YES|NO — <…> 4 Security: YES|NO — <…> 5 Team drag: YES|NO — <…> 6 Benefit: YES|NO — <…> Open question (ASK only): <which question, and what would settle it> ``` Done means every ticket in scope has a record, and every YES cites something a reader can check. ## Closing Closing is **outward-facing**, so the default is a report. Close only what the invoker authorised: this ticket, this list, or "everything that scored CLOSE". First, skip any ticket that is **in flight**, meaning it has an assignee, a milestone, or an open PR that references it. Report those as KEEP, pending their owner: `gh issue view <n> --json assignees,milestone,closedByPullRequestsReferences`. Pick the close reason by *why* the ticket fails the bar. Already fixed on main: `--reason completed`, citing the commit. Covered by another issue: `--reason "not planned"` with "Duplicate of #<m>". Everything else: `--reason "not planned"` with the six answers, so the decision can be read and reversed: ```bash gh issue close <n> --repo <slug> --reason "not planned" --comment "$(cat <<'EOF' Closing against the issue bar (all six impact questions answered NO): - User harm: <…> - Money: <…> - Stability: <…> - Security: <…> - Team drag: <…> - Significant benefit: <…> Reopen with evidence if any of these changes. EOF )" ``` Feature requests and roadmap items: Q6 tells you whether the gain is real and significant, but whether we want it is a product decision. Record the Q6 answer, mark them `ASK — product decision` and move on. ## Before filing The bar applies to a ticket that does not exist yet as well. One more check comes first: if the work is small, fits the change already in flight and needs no design decision, **fix it now** and skip the ticket. For a ticket you do file, write the YES and its evidence into the body, so a later sweep does not have to rebuild the argument, and end the body with a "Filed via <skill>" footer so a sweep can tell it from a human report. Reference related work as `Refs #<n>`. A closing keyword next to another issue's number closes that issue.