Skip to main content
Run this before add-epic, every time an ask arrives — an issue you are about to mirror, a request in conversation, a line off a roadmap doc.

The gap it closes

The conductor has always accepted work. It did not triage it. add-epic validates the id, the lane and the priority, refuses a duplicate externalId, and appends. The only dedup that existed was identity-based — same id, or same externalUrl. That correctly stops /pm:sync from mirroring one issue twice, and it does nothing at all about the same ask arriving under a different name. That failure has exactly one symptom: the backlog only ever grows, and every entry looks equally legitimate.
Measured in PM’s own repository: the change-registered-under-two-lanes integrity check reports four live pairs that are one change registered twice, under different lanes and different names. Identity dedup found none of them. A human reading the backlog did.

Getting the candidate set

--limit N (default 5) bounds how many candidates come back. It must be a positive integer — a valueless or non-numeric --limit is refused rather than coerced, and any other flag is rejected by name. A wrong bound on a recall device silently hides the twin the whole command exists to surface.

The engine computes candidates and never a verdict

This is the line the whole design turns on, and the command states it in its own output: verdict is always null. PM is an instruction layer. An engine that decided two asks were “the same” would be making a semantic judgment on prose, which is exactly the thing it must not do — so it hands you a ranked, auditable candidate set and stops.

Why the ranking has no stoplist

Scoring is IDF over the backlog itselfln((N+1)/df). A term’s weight comes from how rare it is in your own epics, so house vocabulary self-neutralizes: “Implementation Plan” in a title does not drag half the index in, and nobody maintains a curated stopword list that goes stale. Every candidate carries the tokens that earned its score. That is what makes a lexical surface auditable rather than an oracle — you can see at a glance that a match is real, or that it rode in on one shared word.
Triage is not a substitute for the externalUrl check during sync, and that check is not a substitute for triage. They catch different things: identity dedup stops the same item landing twice; triage surfaces the same ask under a different name. Run both.

Declining an ask

An ask you screen and decide against ends the way all work in PM ends — with a recorded disposition carrying its reason, never by deletion:
declined is a terminal outcome, not a status — archived already means terminal, so nothing about status-driven behavior changes. It records that a judgment was made, which is precisely what deletion destroys.

Epics & Lanes

What happens to an ask once you decide to register it.