prompts: add dead_dn_finder (cross-server, story C from threads)

First cross-server prompt landing. Story C from
axl/agent-threads/cross-server-prompts/. Closes a concrete cucx-docs
open finding (orphaned paging DNs 1302 / 1304 at /systems/paging/
carried as "confirm with operator").

A DN is "definitively dead" when:
  1. It exists in numplan but has no devicenumplanmap entry —
     no device claims it as a line (mcaxl, required)
  2. It is not referenced as a UCCX trigger entry point
     (mcuccx, strongly recommended)
  3. It has no recent CDR activity (mcsiphon, optional)

Each layer narrows the candidate set; the intersection is "safe to
retire — verified across CUCM dial plan + UCCX contact center + CDR
activity."

The prompt embodies the architectural decisions confirmed in
cross-server-prompts/002:

  - Per-primary-lens placement (Q1): lives in mcaxl because the
    dial plan is its primary lens
  - Graceful degradation with explicit gaps (Q2): the verdict
    declares MCP availability up-front and adjusts confidence per
    sibling; distinguishes connected-but-broken (include error) from
    not-connected (note "unavailable")
  - Normal naming, no cross_* prefix (Q3): just "dead_dn_finder"

Tier output: "definitively dead" / "likely dead, partial coverage" /
"structurally orphan, unconfirmed" / "active". The cucx-docs paging
DNs (1302, 1304) get explicit name-callouts in the verdict if they
appear, closing the loop back to /systems/paging/.

Tests: registration sentinel updated to 13 prompts. 238/238 passing.

Live-cluster smoke test pending — cucx-docs will run against the
Bingham cluster once they consume this thread direction.
This commit is contained in:
Ryan Malloy 2026-05-05 19:24:23 -06:00
parent a07f8c7291
commit ee1e058559
4 changed files with 251 additions and 0 deletions

View File

@ -20,6 +20,7 @@ shim is where the parameter contract lives.
from . import (
audit_routing,
cucm_sql_help,
dead_dn_finder,
did_block_overlap,
hunt_pilot_audit,
inbound_did_audit,
@ -35,6 +36,7 @@ from . import (
__all__ = [
"audit_routing",
"cucm_sql_help",
"dead_dn_finder",
"did_block_overlap",
"hunt_pilot_audit",
"inbound_did_audit",

View File

@ -0,0 +1,230 @@
"""Cross-server prompt: find DNs that are definitively dead.
A DN is "definitively dead" when:
1. It exists in `numplan` but has no `devicenumplanmap` entry no
device claims it as a line (mcaxl)
2. It is not referenced as a UCCX trigger entry point (mcuccx)
3. It has no recent CDR activity (mcsiphon)
Each layer narrows the candidate set; the final list is "safe to
retire verified across CUCM dial plan + UCCX contact center + CDR
activity." Closes findings of the shape "DN exists in numplan but
nobody knows whose it is" (e.g. orphaned paging DNs that were created
for a use-case that's since been retired).
This is a **cross-server** prompt see
`axl/agent-threads/cross-server-prompts/` for the architectural
discussion that motivated the per-primary-lens placement (this prompt
lives in mcaxl because the dial plan is its primary lens) and the
graceful-degradation behavior when sibling MCPs are unavailable.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from ._common import render_schema_block
if TYPE_CHECKING:
from ..docs_loader import DocsIndex
_KEYWORDS = [
"directory number", "numplan", "device numplan map",
"orphan DN", "paging", "CTI route point",
]
def render(docs: "DocsIndex | None", days_inactive: int = 30) -> str:
"""Find DNs with no device, no UCCX trigger, and no recent CDR
activity the intersection is "definitively dead."
Args:
days_inactive: window for "no recent CDR activity" check, in days.
Default 30. Operator may widen for low-volume DNs (paging,
emergency lines) where 30 days is genuinely quiet.
Required MCP servers:
- mcaxl (always this prompt lives in mcaxl, primary data source)
Strongly recommended:
- mcuccx cross-checks UCCX trigger references. Without it, the
prompt cannot rule out "this DN is a UCCX trigger entry point
even though no CUCM device claims it."
Optional:
- mcsiphon confirms zero CDR activity in the time window.
Without it, the prompt produces a "structurally orphan" verdict
but cannot confirm operational quietness.
"""
schema_block = render_schema_block(
docs, _KEYWORDS, max_chunks=3, max_chars_per_chunk=800
)
return f"""# Dead-DN Finder (cross-server audit)
Find directory numbers that are **definitively dead** exist in the
dial plan but have no claiming device, no UCCX trigger reference, and
no recent CDR activity. The intersection of those three conditions is
"safe to retire" with high confidence.
## MCP availability — declare up-front in the verdict
Before producing the final list, **state which sibling MCP servers are
connected** in your output. This determines the verdict-confidence
level:
- **All three (mcaxl + mcuccx + mcsiphon) connected** "definitively
dead" verdict possible
- **mcaxl + mcuccx, no mcsiphon** "structurally orphan, CDR activity
unconfirmed" — operator may want to widen the time window or check
CDRs manually before retiring
- **mcaxl + mcsiphon, no mcuccx** "no device + no recent activity,
UCCX trigger status unconfirmed" — risk: a paging DN driven by a
UCCX self-service script would falsely qualify
- **mcaxl only** "structurally orphan from CUCM perspective only"
weakest verdict; treat as candidates-for-investigation, not
candidates-for-retirement
If a sibling MCP is **connected but errors mid-call** (different from
not-connected), include the error message in the verdict's confidence
notes a connected-but-broken sibling is its own state.
## Step 1 — Structurally-orphan DNs (mcaxl, required)
Find every DN that exists in `numplan` but has no `devicenumplanmap`
entry claiming it:
```sql
SELECT
np.dnorpattern AS dn,
rp.name AS partition,
np.description,
tpu.name AS pattern_type,
np.alertingname,
np.fkroutepartition AS partition_pkid
FROM numplan np
LEFT OUTER JOIN routepartition rp ON np.fkroutepartition = rp.pkid
LEFT OUTER JOIN typepatternusage tpu ON np.tkpatternusage = tpu.enum
LEFT OUTER JOIN devicenumplanmap m ON m.fknumplan = np.pkid
WHERE m.fknumplan IS NULL
AND tpu.name = 'Device' -- only true DNs, not route patterns
ORDER BY np.dnorpattern;
```
The `LEFT OUTER JOIN ... WHERE m.fknumplan IS NULL` is the
"orphan-detection" idiom DNs that are NOT in the join table.
Filter to `tpu.name = 'Device'` because numplan also holds route
patterns, translation patterns, etc. those are not DNs and aren't
relevant here. Verify the enum name matches by running
`axl_describe_table("typepatternusage")` first if you're unsure.
## Step 2 — UCCX trigger cross-check (mcuccx, strongly recommended)
A DN can be a UCCX trigger entry point even with no CUCM device
claiming it UCCX scripts can answer calls directed at a CTI route
point that fronts the trigger.
If `mcuccx` is connected, call `list_triggers()` and cross-reference
the result against the orphan candidates from Step 1:
- Each UCCX trigger has a `cti_route_point_dn` (or similar field
consult mcuccx's tool output schema) — that's a DN the trigger
answers on
- Remove from the candidate list any DN that appears as a trigger entry
point
If `mcuccx` is **not connected**, note this explicitly in your verdict:
*"UCCX trigger cross-check unavailable (mcuccx not connected); orphan
DNs in the result MAY include trigger entry points verify before
retiring any DN that resembles a contact-center entry point."*
## Step 3 — CDR activity confirmation (mcsiphon, optional)
If `mcsiphon` is connected, for each remaining candidate DN, check
recent CDR activity via `cdr_query_calls(start, end, called_number=DN)`:
- Time window: `{days_inactive}` days back from today
- Field to check: count of returned records; if > 0, the DN had
activity (calls placed to it) in the window
- Note: mcsiphon's CDR records use `dateTimeOrigination_iso_local` —
the values are local-cluster-time, NOT UTC (see
`cucm-schema-cheatsheet.md` for the localization convention). Don't
do timezone conversion on the values.
DNs with zero CDR activity in the window pass this check.
If `mcsiphon` is **not connected**, note this explicitly:
*"CDR activity confirmation unavailable (mcsiphon not connected);
orphan DNs in the result are structurally orphan but operational
quietness is unverified."*
## Step 4 — Verdict per candidate DN
For each remaining DN, produce a structured entry:
```
DN: 1302
Partition: Internal-PT
Description: SNRC Paging
Verdict: definitively dead
Evidence:
- mcaxl: no device claims this DN (no devicenumplanmap entry)
- mcuccx: not referenced as a UCCX trigger
- mcsiphon: zero CDR activity in the last {days_inactive} days
Confidence: high (all three sibling MCPs reported)
Recommended action: safe to retire
```
For partial-coverage cases (some MCPs unavailable), the `Evidence`
block lists what was checked and what was skipped, and `Confidence`
adjusts down accordingly.
## Findings to surface
Group the output by verdict tier:
- **Definitively dead** (passed all three available checks) primary
retirement candidates
- **Likely dead, partial coverage** (passed mcaxl + 1 sibling)
retirement candidates with a verification step required
- **Structurally orphan, CDR/UCCX unconfirmed** (mcaxl-only)
candidates for investigation, not retirement
- **Active** (failed any check) not orphan; do not retire. List
briefly with reason ("appears as UCCX trigger 'PatientIntakeQueue'",
"had 47 calls in the last 30 days", etc.)
## Common-cause cluster of findings
Patterns to watch for in the result:
- **Paging DNs** with descriptions like "All Campus Paging", "<unit>
Paging", "Code <X> Page" — frequently created during initial
deployment and never connected to a real device after the paging
product changed (Algo, InformaCast, native CUCM). Often genuinely
dead; sometimes a forgotten endpoint
- **Conference / IVR DNs** may LOOK orphan from CUCM's perspective
but be UCCX entry points. The mcuccx check is critical here
- **Test / staging DNs** with descriptions naming a tester or a date
almost always safe to retire if the date is > 1 year old
- **Single-DN range patterns** that look like wildcard escapes verify
the pattern is actually a DN (`tpu.name = 'Device'`) and not a route
pattern that happened to match the orphan-detection query
## Reference: DN-vs-pattern semantics, devicenumplanmap join
""" + schema_block + """
Produce a structured findings report grouped by verdict tier. Lead
with the MCP-availability declaration so the operator immediately
sees the confidence level. For each definitively-dead DN, include the
recommended action. For active DNs, list briefly to confirm they were
checked but ruled out don't enumerate every active line.
If `1302` (SNRC Paging) or `1304` (All Campus Paging) appear in the
candidate set, those are explicitly tracked findings on the cucx-docs
side flag them by name in the verdict so the loop closes back to the
`/systems/paging/` page.
"""

View File

@ -560,6 +560,24 @@ def did_block_overlap(block_pattern: str) -> str:
return _prompts.did_block_overlap.render(_docs, block_pattern)
@mcp.prompt
def dead_dn_finder(days_inactive: int = 30) -> str:
"""Find DNs that are definitively dead — exist in numplan but have
no claiming device, no UCCX trigger reference, and no recent CDR
activity. Cross-server prompt: composes mcaxl (required) + mcuccx
(strongly recommended) + mcsiphon (optional). Closes findings of
the shape "DN exists but nobody knows whose it is" the canonical
Bingham example is paging DNs `1302` / `1304` carried as "confirm
with operator" on `/systems/paging/`.
Args:
days_inactive: window for "no recent CDR activity" check, in
days (default 30). Widen for low-volume DNs (paging,
emergency lines) where 30 days is genuinely quiet.
"""
return _prompts.dead_dn_finder.render(_docs, days_inactive)
@mcp.prompt
def partition_summary(partition_name: str | None = None) -> str:
"""Compose a "what is this partition for?" report from existing

View File

@ -171,6 +171,7 @@ def test_all_prompts_registered_in_server():
"whoami",
"did_block_overlap",
"partition_summary",
"dead_dn_finder",
}, f"unexpected prompt set: {names}"