In service-based systems, code frequently persists after it stops participating in execution.
Upstream callers change. User-facing flows are removed. Traffic patterns shift.
The corresponding handlers remain deployed. They compile, pass tests, and emit no errors. From the system’s perspective, nothing is unhealthy.
Prune was built to make that condition inspectable.
The purpose was not automated deletion or correctness guarantees. It was to reconcile declared service contracts with observed runtime execution, using signals already present in production systems.
Declared surface vs executed surface
Most environments already maintain two independent representations of a service.
Static analysis describes the declared surface. Using AST parsing, Prune extracts HTTP handlers directly from code, including method, route template, source file, and line number.
For example:
@app.post("/v1/payments/refund")
def process_refund():
...
This produces a stable contract representation independent of formatting, comments, or refactors.
Observability systems describe execution. Distributed tracing records which paths were actually entered, how often, and when they were last seen.
Each view is accurate in isolation. The problem is that they are rarely compared.
Static analysis cannot establish dependency. Tracing cannot enumerate the full contract surface that exists. When consumed separately, both indicate stability even when relevance has decayed.
Why reconciliation is non-trivial
A direct comparison between declared routes and traced routes does not hold.
Tracing records concrete paths:
/v1/payments/refund/12345
Code defines templated routes:
/v1/payments/refund/{id}
Prune normalizes runtime paths before reconciliation by collapsing numeric identifiers, UUIDs, and long hex segments. Normalization is conservative; ambiguous cases are preserved and marked lower confidence rather than inferred.
This avoids treating representation mismatch as absence of execution.
Filtering non-contract traffic
Not all endpoints represent business behavior.
Health checks, metrics endpoints, readiness probes, and documentation routes are exercised continuously by infrastructure. Their presence is not correlated with product usage.
Prune excludes these endpoints before analysis. The audit is limited to routes whose existence implies a maintained contract.
Interpreting trace evidence
Tracing provides the strongest available signal that a code path executed in a distributed system.
At the same time, it is bounded. Sampling, retention windows, and low-frequency execution paths introduce blind spots.
For this reason, absence of traces is not treated as absence of dependency.
Prune records trace count and last-seen timestamps within a configurable observation window and treats the result as bounded evidence, not a definitive state.
Confidence-based output
Rather than classifying endpoints as alive or dead, Prune assigns confidence tiers.
-
Observed execution is treated as active.
-
Unobserved execution with sufficient evidence becomes a deprecation candidate.
-
Insufficient evidence remains unresolved.
The system does not decide what to delete. It identifies which contracts can be reviewed safely.
Audit output
Prune produces a tabular audit where each row corresponds to a single endpoint.
Example:

The format is intentional. Deletion decisions require traceability to specific contracts and source locations. Aggregates and visual summaries are not useful at this stage.
Intended workflow
Prune does not remove code.
It supports a controlled process:
-
Identify endpoints with no recent execution
-
Shadow-deprecate and log access
-
Observe over an additional window
-
Remove with evidence
This shifts deletion from individual judgment to repeatable procedure.
Scope
Prune does not infer intent, ownership, or future plans. It does not reason about correctness or performance.
It answers one question only:
Does this endpoint still participate in the system’s execution?
That question becomes increasingly difficult to answer as systems grow, even when observability and static tooling are mature.
Why this exists
Unused endpoints do not fail loudly.
They remain correct, deployable, and monitored while expanding review surface, security exposure, and cognitive load.
Prune exists to surface that condition early, while removal is still inexpensive.