Skip to content

[operator] Decide the borrowing-positions contract for dust debt #644

Description

@i-xtsu-sixyou-ken-mei

Decision needed

Decide what the borrowing-positions contract should do with a position whose debt rounds to $0.00. The producer currently emits debt_usd: 0.0 even though it declares gt=0, and the app-core consumer then rejects the whole response. Any fix picks portfolio semantics (drop dust positions vs. accept zero debt), so this is not weak-agent work.

Evidence

  • Sentry ZAP-PILOT-WEB-2: ZodError at positions[6].debt_usd — "Too small: expected number to be >0" — in getBorrowingPositions, 3 events 2026-09-19T07:49:38Z–2026-09-20T10:05:49Z, release 3.0.1. ZAP-PILOT-WEB-4: same error, 1 event at 2026-09-20T10:09:58Z. 0 identified users.
  • Producer: apps/analytics-engine/src/models/borrowing.py declares debt_usd: USDRounded = Field(gt=0.0) (and total_debt_usd the same), where USDRounded = Annotated[float, AfterValidator(_round_usd)] (apps/analytics-engine/src/models/types.py). The bound passes on the raw value, then rounding produces zero. Reproduced locally on main 44736128: BorrowingPosition(debt_usd=0.004, …) validates and dumps debt_usd: 0.0.
  • Consumer: packages/app-core/src/schemas/api/analytics/portfolioSchemas.ts mirrors the declared contract with debt_usd: z.number().positive() and total_debt_usd: z.number().positive(), so one dust row fails the entire borrowing panel.
  • These events started within 15 seconds of [operator] Decide daily-suggestion handling of missing spot prices #643's ANALYTICS-ENGINE-1/2, in the same dashboard session. ops_investigate sentry:stale-unresolved/zap-pilot-web: blockers [], inspectionCoverage inspected, no AUM or customer exposure recorded.

Options

  1. The producer drops positions whose rounded debt is ≤ 0 before building the response, and defines what total_debt_usd / worst_health_rate mean when only dust remains.
  2. Enforce the bound after rounding so the producer never emits an invalid model (on its own this turns the symptom into a producer error; pair it with option 1).
  3. Relax the consumer to nonnegative() and accept zero-debt rows. This changes the published contract, so contract snapshots must be regenerated.

Fingerprint

triage:sentry:ZAP-PILOT-WEB-2

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

    area:analytics-engineScoped to apps/analytics-engineoperatorNeeds production credentials or a human decision; excluded from the agent backlog pool

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions