Skip to content

Contract-name string literals are hardcoded and duplicated across at least seven files, unlike the project's own QueueName pattern for an equivalent concept #135

Description

@dev-fani
  • Labels: refactor, technical-debt, backend
  • Area / component: modules/*/application/sync-*-from-event.ts, modules/*/index.ts

Problem
Every module that filters the shared event bus by originating contract compares event.contractName against a bare string literal ('escrow', 'delivery', 'dispute-resolution', 'fleet', 'identity-reputation') repeated independently in each consumer, and each module's own getTrackedContracts()-style wiring in index.ts independently hardcodes the same string as the value it assigns. No shared constant or literal-union type ties these together, even though the project already uses exactly that pattern for the analogous "canonical name shared between producers and consumers" concept elsewhere.

Current behavior
grep -rln "contractName ===" src/modules/*/application/*.ts confirms the pattern in at least five application-layer files (deliveries, disputes, escrow, fleet, reputation; notifications/fraud-detection add two more via their own switch (event.contractName) dispatch), each independently spelling the exact contract-name string it cares about. src/shared/queue/queues.ts shows the project's own preferred pattern for this exact class of problem — QueueName is a single, shared, as const object whose values producers and consumers both reference, with its own comment explaining why: "Modules reference these constants rather than hardcoding strings, so a rename is a one-line change instead of a grep-and-pray." No equivalent exists for contract names.

Evidence / code location

  • src/modules/deliveries/application/sync-delivery-from-event.ts:23, src/modules/escrow/application/sync-escrow-from-event.ts:26, src/modules/disputes/application/sync-dispute-from-event.ts:51,54, src/modules/fleet/application/sync-fleet-from-event.ts:25, src/modules/reputation/application/sync-reputation-from-event.ts:45 — each module's own hardcoded event.contractName !== '...'/=== '...' check.
  • src/modules/{deliveries,escrow,fleet,disputes,reputation}/index.ts's getTrackedContracts()-equivalent wiring — each independently assigns the matching literal as contractName: '...'.
  • src/shared/queue/queues.ts:10-14 — the QueueName const object, the project's own established pattern for exactly this kind of cross-file string constant, with its own header comment explaining the rationale.

Impact
A single-character typo in any one of these seven-plus locations (e.g., renaming 'dispute-resolution' to 'disputes-resolution' in the indexer's tracked-contract config without updating the disputes module's own comparison) would silently and permanently stop that module from ever matching any event for that contract, with no compile-time error — the strings are compared as plain values, not checked against a shared literal type the compiler could flag a mismatch on.

Expected behavior
Contract names are defined once, as a shared, typed constant every producer and consumer references — mirroring QueueName.

Proposed scope / implementation direction

  1. Add a ContractName const object (mirroring QueueName's shape) to src/shared/events/ or src/blockchain/, with one entry per tracked contract (Escrow: 'escrow', Delivery: 'delivery', DisputeResolution: 'dispute-resolution', Fleet: 'fleet', IdentityReputation: 'identity-reputation').
  2. Type BlockchainEventEnvelope.contractName as ContractNameValue rather than a bare string, so a typo'd comparison anywhere becomes a compile-time type error rather than a silent runtime no-match.
  3. Replace every hardcoded literal (both the index.ts tracked-contract wiring and each application-layer comparison) with the shared constant.

Acceptance criteria

  • Contract names are defined in exactly one place.
  • BlockchainEventEnvelope.contractName is typed against that shared set, not a bare string.
  • All existing sync/dispatch specs and indexer tests pass unchanged.

Verification / testing requirements

  • Existing per-module sync-from-event specs pass unchanged — this is a pure extraction with no behavior change.
  • pnpm typecheck confirms the narrowed type doesn't break any existing call site.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendBackend application coderefactorStructural cleanup without behaviour changetechnical-debtDead code, duplication, or unfinished scaffolding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions