feat(internal): shared venue HTTP transport + secret redaction (06-01 PR1)#36
Conversation
…ate binance/juplend adapters PR1 of 06-01 shared venue infrastructure: extract a venue-agnostic REST transport (src/internal/http-client.ts) and migrate binance catalog, binance private adapter, and juplend adapter onto it. - typed TransportError (kind/retryable/attempts) + isTransportError duck-type guard - per-call retry policy declared at call site: NO_RETRY for orders, SAFE_READ for GETs - secret redaction on error url/message/rawBody (signature/apiKey/listenKey/token) - 429/418 classified as rate_limited + Retry-After parsed, but no retry/sleep - coordinator bootstrap errors re-redacted before AcexError - rate limiter and unified time provider deferred to PR3/PR2
…er-call idempotency, redaction) Add a new Scenario to adapter-contract.md covering src/internal/http-client.ts: venue-injected URL/signing, per-call retry policy (NO_RETRY for writes), typed TransportError instead of AcexError, and the D5 secret-redaction guarantee on error url/message/rawBody. Rate limiter / time provider noted as PR3/PR2 scope. Update backend index entry + change-trigger.
Task artifacts for PR1: prd, implement/check jsonl phases, codex prd review, and the REST migration equivalence matrix.
Session 17: shared venue infrastructure PR1 (REST skeleton + secret redaction).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds a shared TypeScript HTTP client with typed TransportError, secret redaction, retry/backoff and timeout behavior; migrates Binance (catalog & private) and Juplend adapters to use it; maps transport error kinds to runtime reasons in the private subscription coordinator; updates tests, docs, and task tracking. ChangesShared venue HTTP infrastructure
Sequence DiagramsequenceDiagram
participant Adapter
participant httpRequest
participant Fetch as fetch
participant httpClient as Classifier
participant Coordinator
Adapter->>httpRequest: request(options)
httpRequest->>Fetch: perform fetch(url, signal, timeout)
Fetch-->>httpRequest: Response / Error
httpRequest->>httpClient: classify -> TransportError(kind, status)
httpClient->>httpRequest: redactSecrets(url, rawBody)
httpRequest-->>Adapter: HttpClientResponse / TransportError
Adapter->>Coordinator: publish degraded state (TransportError)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.trellis/tasks/06-01-shared-venue-infrastructure/implement.jsonl (1)
8-8:⚠️ Potential issue | 🟠 Major | ⚡ Quick win删除尾部结构不一致的 JSONL 行。
Line 8 的
8不是该清单约定的对象记录,建议移除,避免检查/实现脚本读取异常。💡 建议修复
-8🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.trellis/tasks/06-01-shared-venue-infrastructure/implement.jsonl at line 8, Remove the trailing malformed JSONL record "8" from the file (the standalone line 8) so every line is a valid JSON object as expected by the checklist scripts; edit .trellis/tasks/06-01-shared-venue-infrastructure/implement.jsonl and delete the single-character line "8" (the inconsistent tail record) ensuring the file ends with only well-formed JSONL object records..trellis/tasks/06-01-shared-venue-infrastructure/check.jsonl (1)
9-9:⚠️ Potential issue | 🟠 Major | ⚡ Quick win移除尾部无效 checklist 记录。
Line 9 的裸值
9与前面对象结构不一致,容易在按对象 schema 解析 JSONL 时触发失败或脏数据。💡 建议修复
-9🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.trellis/tasks/06-01-shared-venue-infrastructure/check.jsonl at line 9, Remove the trailing standalone numeric value "9" at the end of check.jsonl (the bare value on line 9) so every line is a valid JSON object matching the checklist schema; ensure the file contains only JSON objects (no naked primitives), re-run a JSONL/schema linter to validate, and commit the cleaned file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/adapters/binance/private-adapter.ts`:
- Around line 167-176: The timeout message hardcodes 10000ms via
BINANCE_PAPI_HTTP_MESSAGES causing misleading errors when httpTimeoutMs is
overridden; change this to a factory that accepts timeoutMs (e.g., implement
getBinancePapiHttpMessages(timeoutMs): HttpClientMessages) and replace
BINANCE_PAPI_HTTP_MESSAGES with that factory, then compute timeoutMs once at
each request site where httpTimeoutMs is used and pass messages:
getBinancePapiHttpMessages(timeoutMs) so the timeout template uses the actual
configured duration.
In `@src/adapters/juplend/private-adapter.ts`:
- Around line 95-99: JUPLEND_HTTP_MESSAGES currently hardcodes the timeout
message to DEFAULT_HTTP_TIMEOUT_MS, causing inaccurate messages when
requestJuplendJson(...) is called with a dynamic httpTimeoutMs; update the
timeout message path in the error messaging flow so the actual timeoutMs passed
to requestJuplendJson (httpTimeoutMs) is used in the text instead of
DEFAULT_HTTP_TIMEOUT_MS—locate JUPLEND_HTTP_MESSAGES and the caller
requestJuplendJson (and its parameter httpTimeoutMs) and change the timeout
message generation to accept and interpolate the runtime timeout value.
In `@src/internal/http-client.ts`:
- Around line 166-177: The current redaction only replaces the signature value
and leaves the rest of the signed query exposed; update the redaction logic
around the redacted variable (the three replace calls in
src/internal/http-client.ts) to detect and redact the entire signed query
fragment (the contiguous query parameters that end with signature=...) rather
than only the signature field. Replace those signature-only replacements with a
single pattern that, when it finds a '?' or '&' followed by any query params
ending in signature=..., replaces the whole fragment with a single stable token
(e.g. "?signed_query=[REDACTED]" or "&signed_query=[REDACTED]") so inputs like
"symbol=...&side=...×tamp=...&signature=..." no longer leak other params;
keep the separate JSON "signature" replacement for object payloads if present.
- Line 289: The retry backoff currently blocks aborts because
delayBeforeRetry(attempt, options.retryPolicy) ignores options.signal; update
delayBeforeRetry to accept and observe an AbortSignal (options.signal) and to
return early by rejecting with an AbortError when the signal is aborted, or
alternatively have httpRequest race the sleep with the signal so the sleep is
cancelled; specifically modify delayBeforeRetry (and any callers in httpRequest)
to check options.signal.aborted before sleeping, attach a signal listener that
rejects the delay promise when triggered, and ensure the rejection propagates so
httpRequest returns immediately on abort instead of waiting the full backoff.
---
Outside diff comments:
In @.trellis/tasks/06-01-shared-venue-infrastructure/check.jsonl:
- Line 9: Remove the trailing standalone numeric value "9" at the end of
check.jsonl (the bare value on line 9) so every line is a valid JSON object
matching the checklist schema; ensure the file contains only JSON objects (no
naked primitives), re-run a JSONL/schema linter to validate, and commit the
cleaned file.
In @.trellis/tasks/06-01-shared-venue-infrastructure/implement.jsonl:
- Line 8: Remove the trailing malformed JSONL record "8" from the file (the
standalone line 8) so every line is a valid JSON object as expected by the
checklist scripts; edit
.trellis/tasks/06-01-shared-venue-infrastructure/implement.jsonl and delete the
single-character line "8" (the inconsistent tail record) ensuring the file ends
with only well-formed JSONL object records.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3e252d46-0665-453a-9f1a-d687417a1996
📒 Files selected for processing (21)
.changeset/redact-transport-error-secrets.md.trellis/spec/backend/adapter-contract.md.trellis/spec/backend/index.md.trellis/tasks/06-01-shared-venue-infrastructure/check.jsonl.trellis/tasks/06-01-shared-venue-infrastructure/codex-prd-review.md.trellis/tasks/06-01-shared-venue-infrastructure/implement.jsonl.trellis/tasks/06-01-shared-venue-infrastructure/pr1-equivalence-matrix.md.trellis/tasks/06-01-shared-venue-infrastructure/prd.md.trellis/tasks/06-01-shared-venue-infrastructure/task.json.trellis/workspace/codex-agent/index.md.trellis/workspace/codex-agent/journal-1.mddocs/multi-venue-roadmap.mdsrc/adapters/binance/market-catalog.tssrc/adapters/binance/private-adapter.tssrc/adapters/juplend/private-adapter.tssrc/client/private-subscription-coordinator.tssrc/internal/http-client.tstests/integration/account.test.tstests/support/exchanges/binance.tstests/support/test-utils.tstests/unit/http-client.test.ts
…d bare signed query, abort-aware retry backoff - binance/juplend: timeout error message reflects the configured httpTimeoutMs instead of the hardcoded default (messages built per-request via factory) - http-client redaction: fold bare/relative signed query fragments to "?query=[REDACTED]" (full URLs were already folded — defense-in-depth) - http-client backoff: delayBeforeRetry observes the abort signal and returns immediately on cancel instead of waiting out the full backoff delay - tests: +2 (abort-during-backoff, bare signed-query redaction) Skipped 2 review findings as false positives: the trailing "8"/"9" flagged in implement.jsonl/check.jsonl were cat -n line numbers, not file content (both files are valid JSONL ending in a clean object).
范围
06-01 共享 venue 基础设施的 PR1:抽出 venue-agnostic 的内部 REST 传输层并迁移现有 adapter。PR2(统一
TimeProvider)与 PR3(rate limiter)不在本 PR。改动
src/internal/http-client.ts:httpRequest+ typedTransportError(kind/retryable/attempts)+isTransportError鸭子 guard(避开跨 bundleinstanceof)+redactSecrets/redactUrl/parseRetryAfterMs。market-catalog、binanceprivate-adapter、juplendprivate-adapter全部改走共享 client;PrivateSubscriptionCoordinator的 bootstrap 错误经redactSecrets再进 publicAcexError。NO_RETRY_POLICY(下单/撤单)、SAFE_READ_RETRY_POLICY(只读 GET)、LISTEN_KEY_KEEPALIVE_RETRY_POLICY。写操作零重试。url/message/rawBody都不再泄漏signature/ apiKey /listenKey/ token / passphrase;venue 注入的messages回调只拿得到已脱敏的输入。rate_limited并解析Retry-After,但不重试、不 sleep(主动退避属 PR3)。等价性
三处 adapter 迁移保持行为等价(method / 重试语义 / 错误 message 文案逐端点核对),唯一 intended diff 是脱敏带来的 message 变化。等价矩阵见
.trellis/tasks/06-01-shared-venue-infrastructure/pr1-equivalence-matrix.md。契约
新增 spec:
adapter-contract.md的「共享 HTTP 传输客户端」Scenario(§3.11–3.16)。测试
bun run lint(biome)✅bun run type-check(tsc --noEmit)✅bun run test✅ 94 pass / 0 fail / 423 expect()Release
附
patchchangeset(beta pre-release):「错误信息不再泄漏签名与密钥」—— 向后兼容行为修复,不改公共类型 / API 形状。Commits
d9bacb6feat(internal): add shared HTTP transport with secret redaction; migrate binance/juplend adaptersdf49fa1docs(spec): document shared HTTP transport contract (REST skeleton, per-call idempotency, redaction)362b6b5chore(task): record 06-01 shared venue infrastructure PR1827a185chore: record journalSummary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests