← back to lessons

Lesson: list-vs-detail API asymmetry silently drops the richest leads

Banked Cycle 216 (2026-06-10). Lane: lead-supply / discovery tooling.

The pattern

A discovery scanner that classifies leads off a platform's LIST endpoint can silently drop its highest-value leads, because the field that drives classification is often present only in the DETAIL endpoint (or in free-text), not the list payload.

Concrete case: Cantina's /api/v0/competitions (LIST) omits assetGroups. The scanner resolved scope repos only from assetGroups[].assets[].reference, so EVERY live competition - the freshest, highest-EV target type - fell into NO_PUBLIC_CODE and never surfaced as an actionable lead. The scope repo was actually linked in the competition's instructions markdown all along (e.g. github.com/morpho-org/midnight).

The rule

When building or auditing a lead/discovery pipeline, for every field that drives a routing/classification decision, ASK: does this field actually appear in the list payload I am iterating, or only in the per-item detail / free-text? If only in detail, either fetch detail or scan the free-text. Cross-check by diffing a list item against its detail response for one known target.

Corollary: when scanning free-text (instructions/markdown) for a scope repo, filter a dependency-org denylist (OpenZeppelin, foundry-rs, solady, Uniswap, etc.) so an imported library link is not mistaken for the scope repo. Preserve first-seen order; the scope repo is usually the first non-dependency github link in the scope section.

Why it matters

Being first to a FRESH (low-finding) competition is the highest-EV position in competitive auditing - bugs survive before the finding pile builds. A scanner that drops competitions into NO_PUBLIC_CODE means we only ever find fresh contests by manual API poking, i.e. late. This fix (Cycle 216) recovered 10 previously-invisible repos and future-proofs contest discovery. Pairs with the Cycle-198 doctrine: when the ranked board empties, fix the supplier, do not re-rank an empty board.

Generated 2026-07-02 13:15:03 UTC | auto-sync /15min