Skip to content

[DBIP] Validate that listing offer references resolve #1948

Description

@jaasieldelgado131

Summary

Many listing rows use canonical !offer:<slug> references, but the referenced offer slug does not exist anywhere under references/offers/**/*.csv. A category-match validator can only run after the slug resolves; these dangling references should fail earlier with a clear error.

Evidence

Local CSV scan on current main found:

  • 1,198 defined offer slugs under references/offers/**/*.csv
  • 12,727 listing cells using !offer:<slug>
  • 1,068 listing !offer: references that do not resolve to any defined offer slug

Concrete examples:

listing row unresolved reference
listings/all-networks/platforms.csv:21 !offer:superchain-dev-console
listings/all-networks/sdks.csv:2 !offer:alchemy-sdk-enterprise
listings/all-networks/services.csv:2 !offer:alchemy-bundler-enterprise
listings/specific-networks/abstract/wallets.csv:2 !offer:safe-gnosis
listings/specific-networks/algorand/bridges.csv:3 !offer:messina
listings/specific-networks/algorand/oracles.csv:2 !offer:goracle
listings/specific-networks/algorand/wallets.csv:21 !offer:trustwallet
listings/specific-networks/aptos/services.csv:2 !offer:alchemy-bundler-free

Why this matters

The README and agent guidance describe listings as consuming canonical offers through !offer:<slug>. If a slug is missing, downstream consumers cannot reliably hydrate the listing from the provider -> offer -> listing graph. The row may still look populated in CSV form, but the canonical relationship is broken.

This is distinct from #1946, which covers !offer: references that resolve but point to an offer defined in the wrong category file. This proposal covers references that do not resolve at all.

Detailed proposal

Add a validation guardrail for listing rows that use !offer:<slug>:

  1. Build the set of valid slugs from every references/offers/**/*.csv row.
  2. For each listings/**/*.csv row with an offer value starting with !offer:, require that the slug exists in that set.
  3. Emit a row-level error with file path, line number, and unresolved slug.
  4. Run this before any category-match or export hydration validation so missing references fail clearly.
  5. If legacy dangling references must remain temporarily, add an explicit allowlist with comments and an expiry/removal plan.

Reproduction sketch

import csv, pathlib
root = pathlib.Path('.')
offers = set()
for p in (root / 'references/offers').rglob('*.csv'):
    for row in csv.DictReader(p.open(encoding='utf-8-sig', newline='')):
        slug = (row.get('offer') or row.get('id') or row.get('slug') or '').strip()
        if slug:
            offers.add(f'!offer:{slug}')

missing = []
for p in (root / 'listings').rglob('*.csv'):
    for i, row in enumerate(csv.DictReader(p.open(encoding='utf-8-sig', newline='')), start=2):
        ref = (row.get('offer') or '').strip()
        if ref.startswith('!offer:') and ref not in offers:
            missing.append((str(p), i, ref))
print(len(missing))

Reward address

Public ERC-20 address for the DBIP reward, if approved:

0xb43d90BB4E22A43D77e9bfbc2f1CA826ec1CaBF1

Metadata

Metadata

Assignees

No one assigned

    Labels

    DBIPFor database improvement proposals

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions