dsh-batch-triage

workflownpmApache-2.0

Deterministic ticket triage: a rule prefilter classifies clear cases and returns everything else as needs_review instead of guessing.

下载量 / Downloads
545

Install

dsh plugin --profile web add dsh-batch-triage

Sandbox test

This plugin has not been tested yet. Submit a test →

README

dsh-batch-triage

**Rules decide the easy tickets. Anything the rules cannot place is handed to a

human — never quietly filed as routine.**

A DeepSeek Harness plugin.

No model, no service, no network, no API key.

$ node -e "
  import('dsh-batch-triage').then(m => {
    const r = m.triageBatch([
      { id: 'a', text: 'The service is down for all users' },
      { id: 'b', text: 'How do I install this on Windows?' },
      { id: 'c', text: 'The frobnitz is blorp.' },
    ], m.resolveConfig({}));
    console.log(r.items.map(i => i.id + ' ' + i.class + '  ' + i.reasonCodes[0]).join('\n'));
    console.log('exit', r.exitCode, r.exitBasis);
  })"

a urgent        OUTAGE_REPORTED
b routine       INSTALL_QUESTION
c needs_review  NO_RULE_MATCHED
exit 6 modelUnavailable

Quick start

dsh plugin --profile web add dsh-batch-triage@0.1.4

batch_triage is now available; Rules place the tickets they can; anything they cannot place is returned as needs_review — never quietly filed as routine.

Why rules first

A ticket batch is the wrong shape for one model call per item: the volume is high,

the interesting items are few, and every item costs a round trip whether or not it

needed one. So the order is inverted from the obvious one.

The prefilter runs on every item, first. Rules place the clear cases — a crash

with a stack trace is urgent, "how do I install this" is routine — and they place

them without asking anything. Only the residue would ever reach a model, and this

release does not reach one at all: it says so instead.

That ordering is not an optimisation. It is the design's main path, and it changes

what the tool is for: the prefilter is the product, and the model is a fallback.

The rule that matters most

An item is never routine unless a rule said so.

Every path that cannot classify — an empty body, no matching rule, no model

configured, a budget exhausted — produces needs_review. Turning "I could not

tell" into "nothing to see here" is the one failure this tool exists to prevent,

and the test suite pins it in both directions.

0.1.2 tightened what "a rule said so" is allowed to mean. A rule decides on a

phrase, and a ticket has more than one sentence: when the phrase that matched is a

question and another sentence reports something broken, the question rule does not get

to decide the ticket. It becomes needs_review with MALFUNCTION_REPORTED, and the

rule that would have swallowed it stays in reasonCodes so a reader sees both halves.

decidedBy says which tier actually decided:

value · meaning

prefilter · a rule placed it; reasonCodes names which

unavailable · nothing could place it and no model tier is configured

budget · a cap was reached, so it was not assessed

The last two both carry escalate: true. Neither is a verdict about the ticket.

What the rules look at

A structured field outranks the body text: severity: critical,

security: true, data_loss: true, reporter_tier: enterprise. A reporter who

filled in a form has already told you, and no wording in the body can lower what the

field said. Wording that reports something worse still raises it — a field can never

bury an outage, and when the two disagree the item carries both reason codes.

Otherwise the highest class any rule claims wins, and the table is written

strongest first so that a tie inside a class goes to the rule listed first:

class · rules

urgent · outage, data_loss, security, crash_with_trace, blocked_workflow

needs_review · regression, wrong_result, performance, flaky

routine · install_question, usage_question, documentation, feature_request, thanks

A ticket that reports an outage and phrases itself as a question must not be

swallowed by the question rule. That is a test — and in 0.1.1 it was a test that could

not fail, because its fixture used wording the outage rule already recognised, so the

fixture and the rule shared an assumption and the precedence was never really exercised.

Precedence is by class rather than by position now, which also means a caller-supplied

rules array cannot reorder the table into a fail-open.

Class precedence alone was not enough, and the six measured tickets below are why.

outage did not know "returns 500 for every request", so no severity rule matched,

and the question rule decided the whole ticket from one sentence of it. So a routine

verdict gets one more check: if the body reports a malfunction — an error, a crash,

something "unusable", a 5xx, deleted records, a leaked credential — in wording no

severity rule could name, the item becomes needs_review with MALFUNCTION_REPORTED

instead of routine. That guard only ever refuses a routine; it cannot raise

anything to urgent, and it cannot touch a verdict a severity rule already made.

Precedence by class is chosen over "most specific wins" deliberately. A scoring system

would need weights nobody could defend; a class ladder needs none, and the table stays

inspectable — a rule that never fires is a bug you can see.

The wordings the fix was measured against, verbatim from the audit. All six were

routine with exit 0 on 0.1.1:

ticket · 0.1.1 · 0.1.2

How do I install this? Also our production API returns 500 for every request. · routine INSTALL_QUESTION, exit 0 · urgent OUTAGE_REPORTED, exit 1

Is there documentation for the auth flow? We are seeing records deleted from our database. · routine DOCUMENTATION_REQUEST, exit 0 · urgent DATA_LOSS_REPORTED, exit 1

Feature request: please add CSV export. Meanwhile the app is unusable for our whole team. · routine FEATURE_REQUEST, exit 0 · urgent OUTAGE_REPORTED, exit 1

How do I configure SSRF protection? Our pentest found we can read other users files. · routine `INSTALL_QUESTION

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::6,最后更新 2026-10-20

Links

GitHub · Homepage · npm

Same category