honeymaker 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8386a3ce395f193a10d210d48e62f48ffb5f2c2cf6ab2dbf77cd8a6466700c9
4
- data.tar.gz: 9a4bd23725e93deb9a4b8e6aad1f9e86f6b27f13ecf0507031a9fbd53b2f65ba
3
+ metadata.gz: c0d4a030c628dda5a597efb6ff65b552ce961cfb855e7f6affa668a8f0e6f492
4
+ data.tar.gz: 43372bdcc5a896dcf83e7f8fcd913d091a1b2c79b61e03e2b1e430dc20821ee0
5
5
  SHA512:
6
- metadata.gz: 76f414d30b7ae364453bdb8b0522e2c1be01adc6db1126addfc2d0f3fc7111df3d3de41714dab6ec98b25dba8116605f9a9c064a58fe907aba2a4eb24f3f81f5
7
- data.tar.gz: b6d38bc14208cadd407faa789607deddba96a9bd0a5c63d0ed5efbbc6fc86bef6fadda21f30814051e0cae5c1ded2a1bba8a8f5e2a99f06074dffb9c545f9229
6
+ metadata.gz: aabd7c7f6859af5e36fb7bc301a227603683b9505e78a306b3944b8fba8ed6c5df45c05a9846557b18c59f461bfe3601f7492ede5a02c6125a87a1d9d58e76fe
7
+ data.tar.gz: ef8db9f4be0d5d60aa65a0d9baa41283b20cf44ddf6f624b4c0617cc5fab6449ac77878b190d0dff2ebca848876461a500b95d6b53f39f9b465fa817567ad923
@@ -70,8 +70,19 @@ module Honeymaker
70
70
  status = e.respond_to?(:response_status) ? e.response_status : nil
71
71
  Result::Failure.new(error_message, data: { status: status })
72
72
  rescue StandardError => e
73
+ # NOT an exchange error — a bug here, in a vendor gem, or in the caller, and it arrives in the
74
+ # same Result::Failure as a genuine venue rejection. Callers classify that text to decide "out
75
+ # of funds" / "bad key" / "safe to retry", so an unlabelled TypeError gets attributed to the
76
+ # exchange: a hyperliquid-rb signing crash sat in production order history for three months
77
+ # reading exactly like a venue rejection. Name the class so the true source is unmistakable,
78
+ # and flag it so a caller can refuse to classify it as the venue's at all.
79
+ #
80
+ # The class is a PREFIX, not a replacement: the network failures that also land here
81
+ # (Net::ReadTimeout, execution expired, connection refused) are matched by substring for
82
+ # transient retry, and those matches must keep working.
73
83
  msg = e.message
74
- Result::Failure.new((msg && !msg.empty?) ? msg : "Unknown error")
84
+ labelled = (msg && !msg.empty?) ? "#{e.class}: #{msg}" : e.class.to_s
85
+ Result::Failure.new(labelled, data: { client_error: true })
75
86
  end
76
87
 
77
88
  # A business error the exchange returned inside an HTTP-200 envelope (KuCoin's non-"200000"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Honeymaker
4
- VERSION = "0.11.0"
4
+ VERSION = "0.11.1"
5
5
  end
@@ -41,7 +41,44 @@ class Honeymaker::ClientTest < Minitest::Test
41
41
  client = Honeymaker::Client.new
42
42
  result = client.send(:with_rescue) { raise StandardError, "boom" }
43
43
  assert result.failure?
44
- assert_equal ["boom"], result.errors
44
+ assert_equal ["StandardError: boom"], result.errors
45
+ end
46
+
47
+ # A bug in this gem, in a vendor gem, or in the caller is NOT an exchange error, but it lands in
48
+ # the same Result::Failure. Callers classify failure text to decide "out of funds" / "bad key" /
49
+ # "retry me", so an unlabelled TypeError reads as something the venue said and gets filed and
50
+ # reported as one. Naming the class makes the true source unmistakable, and the flag lets a
51
+ # caller refuse to classify it at all.
52
+ def test_with_rescue_names_the_exception_class_for_non_api_errors
53
+ client = Honeymaker::Client.new
54
+ result = client.send(:with_rescue) { raise TypeError, "String can't be coerced into Float" }
55
+ assert result.failure?
56
+ assert_equal ["TypeError: String can't be coerced into Float"], result.errors
57
+ assert result.data[:client_error], "a local exception must be flagged, not passed off as the venue's"
58
+ end
59
+
60
+ def test_with_rescue_labels_an_empty_message_with_its_class
61
+ client = Honeymaker::Client.new
62
+ result = client.send(:with_rescue) { raise NoMethodError, "" }
63
+ assert result.failure?
64
+ assert_equal ["NoMethodError"], result.errors
65
+ end
66
+
67
+ # Network failures reach callers through this branch too, and the transient-retry matchers key
68
+ # off substrings of them. Prefixing must not break that.
69
+ def test_with_rescue_keeps_network_substrings_matchable
70
+ client = Honeymaker::Client.new
71
+ result = client.send(:with_rescue) { raise Net::ReadTimeout, "Net::ReadTimeout with #<TCPSocket:(closed)>" }
72
+ assert_includes result.errors.first, "Net::ReadTimeout"
73
+ end
74
+
75
+ # An exchange error is not ours: it must stay unflagged and unprefixed so the venue's own text
76
+ # reaches the classifiers verbatim.
77
+ def test_with_rescue_does_not_flag_api_errors
78
+ client = Honeymaker::Client.new
79
+ result = client.send(:with_rescue) { raise Faraday::TimeoutError, "timeout" }
80
+ assert result.failure?
81
+ assert_nil result.data[:client_error]
45
82
  end
46
83
 
47
84
  def test_hmac_sha256
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeymaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Deltabadger