Handle empty appraisal API responses deterministically - #285
Merged
karagozemin merged 1 commit intoAug 31, 2026
Conversation
|
@ayomustap Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verification
▶ appraisal schema fixtures load
�[32m✔ every fixture parses as JSON �[90m(0.799438ms)�[39m�[39m
�[32m✔ valid-response carries the appraisal model id �[90m(0.166213ms)�[39m�[39m
�[32m✔ valid-response inputsHash matches the canonical request hash �[90m(0.469412ms)�[39m�[39m
�[32m✔ appraisal schema fixtures load �[90m(2.417427ms)�[39m�[39m
▶ valid request fixture
�[32m✔ parses cleanly and preserves the canonical inputsHash �[90m(0.446209ms)�[39m�[39m
�[32m✔ produces the exact appraisal the response fixture documents �[90m(0.344724ms)�[39m�[39m
�[32m✔ valid request fixture �[90m(0.950691ms)�[39m�[39m
▶ missing fields fixture
�[32m✔ rejects with a stable error message naming itemRef �[90m(0.248572ms)�[39m�[39m
�[32m✔ missing fields fixture �[90m(0.409411ms)�[39m�[39m
▶ wrong types fixture — full validation cascade
�[32m✔ first field check (itemRef) reports the type violation �[90m(0.873926ms)�[39m�[39m
�[32m✔ with itemRef repaired, basePrice type violation surfaces next �[90m(0.202038ms)�[39m�[39m
�[32m✔ category as object surfaces
category must be a string�[90m(0.172469ms)�[39m�[39m�[32m✔ attributes as bare string surfaces
attributes must be an object�[90m(0.280039ms)�[39m�[39m�[32m✔ wrong types fixture — full validation cascade �[90m(1.776679ms)�[39m�[39m
▶ oversized text fixture
�[32m✔ rejects itemRef strings past the documented length bound �[90m(0.353871ms)�[39m�[39m
�[32m✔ category length bound is enforced when itemRef is valid �[90m(0.294023ms)�[39m�[39m
�[32m✔ exactly-MAX_ITEMREF_LENGTH itemRef is accepted (off-by-one guard) �[90m(0.141911ms)�[39m�[39m
�[32m✔ exactly-MAX_CATEGORY_LENGTH category is accepted (off-by-one guard) �[90m(0.070573ms)�[39m�[39m
�[32m✔ oversized text fixture �[90m(1.073225ms)�[39m�[39m
▶ invalid score values fixture — full cascade
�[32m✔ first bad score (quality as string) is reported �[90m(0.16699ms)�[39m�[39m
�[32m✔ quality repaired → demand null surfaces next �[90m(0.141673ms)�[39m�[39m
�[32m✔ quality+demand repaired → scarcity as object surfaces next �[90m(0.074816ms)�[39m�[39m
�[32m✔ quality+demand+scarcity repaired → risk boolean surfaces last �[90m(0.092601ms)�[39m�[39m
�[32m✔ numeric scores out of [0,100] are clamped (intentional scoring semantic) �[90m(0.263848ms)�[39m�[39m
�[32m✔ invalid score values fixture — full cascade �[90m(0.865818ms)�[39m�[39m
�[32m✔ appraisal is deterministic — identical inputs give identical output �[90m(1.724573ms)�[39m�[39m
�[32m✔ inputsHash ignores property order (canonical form) �[90m(1.204815ms)�[39m�[39m
�[32m✔ higher risk lowers value; higher quality/demand/scarcity raises it �[90m(0.430904ms)�[39m�[39m
�[32m✔ confidence increases with the number of supplied attributes �[90m(0.208992ms)�[39m�[39m
�[32m✔ suggested max bid never exceeds fair value (preserves margin) �[90m(0.210086ms)�[39m�[39m
�[32m✔ unknown category falls back to a neutral multiplier �[90m(0.187088ms)�[39m�[39m
�[32m✔ parseAppraisalRequest validates and clamps �[90m(0.644484ms)�[39m�[39m
▶ createPaidFetch response parsing
�[32m✔ throws a typed parse error for an unpaid empty response body �[90m(3.738808ms)�[39m�[39m
�[32m✔ throws a typed parse error for a paid non-JSON response body without exposing raw content �[90m(2.714588ms)�[39m�[39m
�[32m✔ preserves x402 payment errors for non-JSON 402 responses �[90m(1.616043ms)�[39m�[39m
�[32m✔ createPaidFetch response parsing �[90m(8.990905ms)�[39m�[39m
▶ configFromEnv valid configurations
�[32m✔ builds a minimal testnet config with safe defaults �[90m(2.59578ms)�[39m�[39m
�[32m✔ accepts explicit testnet overrides �[90m(1.167375ms)�[39m�[39m
�[32m✔ uses pubnet USDC when pubnet and its RPC are configured �[90m(0.952075ms)�[39m�[39m
�[32m✔ configFromEnv valid configurations �[90m(5.807851ms)�[39m�[39m
▶ configFromEnv failure modes
�[32m✔ names missing required variables �[90m(0.936429ms)�[39m�[39m
�[32m✔ rejects malformed PRICE values �[90m(3.972648ms)�[39m�[39m
�[32m✔ rejects invalid PORT values �[90m(2.675845ms)�[39m�[39m
�[32m✔ rejects unsupported networks �[90m(0.311201ms)�[39m�[39m
�[32m✔ rejects a network/passphrase mismatch �[90m(0.275614ms)�[39m�[39m
�[32m✔ requires a custom RPC URL for pubnet �[90m(1.318114ms)�[39m�[39m
�[32m✔ rejects malformed Stellar keys and addresses �[90m(1.952362ms)�[39m�[39m
�[32m✔ rejects malformed RPC URLs �[90m(1.20971ms)�[39m�[39m
�[32m✔ configFromEnv failure modes �[90m(13.327762ms)�[39m�[39m
�[34mℹ tests 40�[39m
�[34mℹ suites 9�[39m
�[34mℹ pass 40�[39m
�[34mℹ fail 0�[39m
�[34mℹ cancelled 0�[39m
�[34mℹ skipped 0�[39m
�[34mℹ todo 0�[39m
�[34mℹ duration_ms 2845.020853�[39m
Closes #277