Skip to content

fix(providers): bound successful OAuth and webhook responses#98098

Merged
steipete merged 1 commit into
openclaw:mainfrom
lwy-2:fix/bound-nextcloud-discord-response-reads
Jul 6, 2026
Merged

fix(providers): bound successful OAuth and webhook responses#98098
steipete merged 1 commit into
openclaw:mainfrom
lwy-2:fix/bound-nextcloud-discord-response-reads

Conversation

@lwy-2

@lwy-2 lwy-2 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Caps successful JSON response bodies in the two provider-controlled paths that were still unbounded on current main:

  • Discord webhook execution responses.
  • OpenRouter OAuth code exchange responses.

The original Google path was removed because fetchWithTimeout already applies the same 16 MiB response cap. The proposed Nextcloud path was also already fixed on main.

Why This Change Was Made

Both remaining paths now use the shared readProviderJsonResponse helper, which rejects and cancels oversized streams. Discord keeps its existing transport contract: wait=false 204 responses require no body, and malformed or oversized optional bodies after a successful non-idempotent POST do not turn the completed send into an error that could trigger a duplicate bot fallback.

User Impact

  • Hostile or broken successful OpenRouter responses cannot be buffered without a bound.
  • Successful Discord webhook sends remain successful even when Discord's optional response body is absent, malformed, or oversized.
  • No new configuration or compatibility surface.

Evidence

  • Blacksmith Testbox focused run 28775960314: formatting plus 12 Discord webhook and 9 OpenRouter OAuth tests passed.
  • Blacksmith Testbox changed gate 28776116220: extension typechecks, test typechecks, lint, dependency guards, database-first guard, sidecar checks, and import-cycle checks passed.
  • Oversized-stream tests verify rejection/cancellation for OpenRouter and cancellation without duplicate-send failure for Discord.
  • Live unauthenticated probes reached the current Discord, OpenRouter, and Google JSON error endpoints; no credentials or external writes were used.
  • Fresh autoreview: clean after fixing duplicate-send semantics and generic typing.

Closes no issue.

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord channel: nextcloud-talk Channel integration: nextcloud-talk extensions: google extensions: openrouter size: XS and removed channel: nextcloud-talk Channel integration: nextcloud-talk labels Jun 30, 2026
@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 2, 2026, 9:35 PM ET / 01:35 UTC.

Summary
The PR bounds Discord webhook success-body parsing and Google/OpenRouter OAuth token response reads with shared provider HTTP readers while preserving Discord 204 no-body success.

PR surface: Source +15. Total +15 across 3 files.

Reproducibility: yes. Current main has unbounded response.text()/response.json() reads in the touched success and error paths, and the PR body provides after-fix loopback terminal output for normal, oversized, malformed, and 204 cases; I did not run tests locally because this review is read-only.

Review metrics: 2 noteworthy metrics.

  • Runtime response reads: 3 changed. All changed paths consume external HTTP response bodies, so review hinges on normal, empty, malformed, and oversized response behavior.
  • Open overlap: 3 related open PRs found. At least one open PR overlaps Discord and two overlap OpenRouter/Google OAuth, so merge order can affect the final landed shape.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Coordinate merge order with the overlapping bounded-read PRs.
  • [P2] Add focused regression tests for the new 204 and bounded success-read branches if maintainers want durable coverage before landing.

Risk before merge

  • [P1] Auth-provider behavior changes: malformed or oversized successful Google/OpenRouter OAuth token responses now fail with explicit parser/overflow errors instead of following the previous unbounded/truncating behavior.
  • [P1] Message-delivery behavior changes: Discord 204 no-body success is preserved, but other successful webhook responses must now be bounded valid JSON instead of falling back to an empty send result on parse failure.
  • [P1] Several open bounded-read PRs overlap parts of this surface, so maintainers should choose merge order carefully to avoid conflicts or diverging cap/error semantics.

Maintainer options:

  1. Accept Explicit Failure Hardening (recommended)
    Maintainers can accept the new overflow/malformed-success failures as the intended safety tradeoff after the supplied loopback proof.
  2. Coordinate The Overlap Before Merge
    Review merge order against the open bounded-read PRs so Discord, Google, and OpenRouter do not land with conflicting cap or fallback semantics.
  3. Split If Maintainers Prefer Narrow Canonicals
    If the overlap is too noisy, keep only the most useful surface here and let narrower proof-positive PRs own the remaining paths.

Next step before merge

  • No automated repair is needed; the remaining action is maintainer review of merge order and the intended fail-closed behavior.

Security
Cleared: No supply-chain, workflow, dependency, permission, or secret-handling concern was found; the diff narrows memory-exhaustion exposure by bounding external response reads.

Review details

Best possible solution:

Land one canonical bounded-read implementation for these exact paths, keeping the shared SDK readers and Discord 204 guard while coordinating merge order with the overlapping bounded-read PRs.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main has unbounded response.text()/response.json() reads in the touched success and error paths, and the PR body provides after-fix loopback terminal output for normal, oversized, malformed, and 204 cases; I did not run tests locally because this review is read-only.

Is this the best way to solve the issue?

Yes. Reusing readProviderJsonResponse/readResponseTextLimited at the plugin-owned call sites is the narrowest maintainable fix; custom per-provider readers or continued parse fallbacks would duplicate the SDK contract or weaken explicit overflow signaling.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 4440226d52c2.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body contains copied loopback terminal output that exercises the final changed Discord, Google, and OpenRouter paths on normal and oversized responses, including Discord 204 handling.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body contains copied loopback terminal output that exercises the final changed Discord, Google, and OpenRouter paths on normal and oversized responses, including Discord 204 handling.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: 🔁 re-review loop: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This is focused plugin/auth resource-exhaustion hardening with limited blast radius and no evidence of a current outage.
  • merge-risk: 🚨 auth-provider: The PR changes Google and OpenRouter OAuth token response parsing and overflow failure behavior.
  • merge-risk: 🚨 message-delivery: The PR changes Discord webhook success-response parsing and can surface malformed or oversized successful webhook bodies as send failures.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body contains copied loopback terminal output that exercises the final changed Discord, Google, and OpenRouter paths on normal and oversized responses, including Discord 204 handling.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body contains copied loopback terminal output that exercises the final changed Discord, Google, and OpenRouter paths on normal and oversized responses, including Discord 204 handling.
Evidence reviewed

PR surface:

Source +15. Total +15 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 3 29 14 +15
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 29 14 +15

What I checked:

  • Root policy read: Root AGENTS.md was read fully; its PR review, plugin-boundary, proof, and compatibility/merge-risk guidance applies to this review. (AGENTS.md:1, 4440226d52c2)
  • Scoped extension policy read: extensions/AGENTS.md was read fully; the touched bundled plugin files use allowed openclaw/plugin-sdk subpaths and stay inside the extension boundary. (extensions/AGENTS.md:1, 4440226d52c2)
  • Current main Discord behavior: Current main supports a webhook wait option and falls back to an empty payload when successful response.json() fails, leaving the success-body read unbounded but tolerant of empty/non-JSON bodies. (extensions/discord/src/send.webhook.ts:124, 4440226d52c2)
  • PR head Discord behavior: The PR head uses readProviderJsonResponse for successful webhook bodies and preserves the 204 no-body case before parsing JSON. (extensions/discord/src/send.webhook.ts:127, fbbab0d3ccf9)
  • Current main Google OAuth reads: Current main reads Google token exchange error text and successful JSON with response.text()/response.json(), so both paths can buffer provider-sized bodies. (extensions/google/oauth.token.ts:30, 4440226d52c2)
  • PR head Google OAuth reads: The PR head bounds Google token error text at 4 KiB and success JSON through readProviderJsonResponse with the shared 16 MiB default cap. (extensions/google/oauth.token.ts:33, fbbab0d3ccf9)

Likely related people:

  • vincentkoc: Available history shows commit e085fa1 adding the current Discord webhook, Google OAuth token, OpenRouter OAuth, and shared provider HTTP helper files; shortlog also shows Vincent Koc as the largest sampled contributor across these paths. (role: recent area contributor; confidence: medium; commits: e085fa1a3ffd; files: extensions/discord/src/send.webhook.ts, extensions/google/oauth.token.ts, extensions/openrouter/oauth.ts)
  • steipete: Peter Steinberger split the Google OAuth token module and cleaned plugin SDK provider boundaries that this PR uses. (role: adjacent feature owner; confidence: medium; commits: 92e765cdee15, ce9dff14581f; files: extensions/google/oauth.token.ts, src/plugin-sdk/provider-http.ts)
  • scoootscooob: scoootscooob moved the Discord channel implementation into extensions, which is the current owner boundary for the touched webhook send path. (role: Discord migration contributor; confidence: medium; commits: 5682ec37fada; files: extensions/discord/src/send.ts, extensions/discord/src/send.webhook.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. labels Jun 30, 2026
@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Hi maintainers 👋 Could a maintainer please Approve and run the pending workflows? The key checks should pass. Thanks!

@lwy-2
lwy-2 force-pushed the fix/bound-nextcloud-discord-response-reads branch from fea9a02 to 60292e2 Compare July 1, 2026 01:33
@openclaw-barnacle openclaw-barnacle Bot added the channel: nextcloud-talk Channel integration: nextcloud-talk label Jul 1, 2026
@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@openclaw-barnacle openclaw-barnacle Bot removed the channel: nextcloud-talk Channel integration: nextcloud-talk label Jul 1, 2026
@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Fixed OpenRouter OAuth: replaced readResponseTextLimited (silent truncation) with readProviderJsonResponse (explicit overflow error) for the success path, as recommended by ClawSweeper. Added before/after terminal comparison showing all three bounded-read scenarios.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed ClawSweeper findings:

  1. Discord webhook: removed .catch(() => ({})) so readProviderJsonResponse overflow errors propagate explicitly instead of being swallowed
  2. PR body: removed stale Nextcloud claims (path no longer in diff), added Google-specific proof, updated Discord overflow description
  3. Diff now matches PR body — exactly 3 files (Discord, Google, OpenRouter)

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Updated PR body with comprehensive real behavior proof following the same pattern as PR #98260:

  • Detailed before/after behavioral assertions with terminal output
  • Overflow check logic verification with real execution
  • Per-file behavioral description with negative controls
  • Full test output with specific test names

@clawsweeper re-review

@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Restructured PR body with proper ## Real behavior proof section containing: Behavior addressed, Real environment tested, Exact steps or command run after this patch, Evidence after fix (with terminal output and diff-level proof), and What was not tested.

@clawsweeper re-review

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. label Jul 1, 2026
@lwy-2

lwy-2 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Fixed Discord 204 No Content regression:

  • Added explicit response.status === 204 check before readProviderJsonResponse
  • wait:false webhook execution now returns {} without hitting the bounded JSON parser
  • wait:true (default) still uses bounded readProviderJsonResponse with overflow signaling
  • Tests pass (162 files, 1816 passed)

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 1, 2026
@lwy-2

lwy-2 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Added loopback proof with local HTTP server simulating real API responses for all 6 scenarios:

  1. Discord wait:true JSON body ✅
  2. Discord wait:false 204 No Content ✅
  3. Discord oversized response (>1MB) rejected ✅
  4. OpenRouter OAuth token parsed ✅
  5. Google OAuth token parsed ✅
  6. Google OAuth error body bounded at 4KB ✅

@clawsweeper re-review

@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jul 2, 2026
@clawsweeper clawsweeper Bot added the status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. label Jul 2, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 2, 2026
@lwy-2

lwy-2 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. labels Jul 3, 2026
@steipete steipete self-assigned this Jul 6, 2026
@steipete
steipete force-pushed the fix/bound-nextcloud-discord-response-reads branch from fbbab0d to 2b747ee Compare July 6, 2026 07:55
@steipete steipete changed the title fix(nextcloud-talk,discord): bound response body reads for webhook and error paths fix(providers): bound successful OAuth and webhook responses Jul 6, 2026
@steipete
steipete merged commit f1f8c1e into openclaw:main Jul 6, 2026
103 of 106 checks passed
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 8, 2026
…mantics

The thread-ownership 409 conflict path still used unbounded resp.json(),
inconsistent with the bounded readers shipped across the other channel/provider
success paths. A compromised or buggy forwarder returning a multi-GB 409 body
would buffer the entire body before JSON.parse, OOMing the agent.

Bound the 409 body via readResponseTextLimited (8 KiB cap; a 409 owner field is
~30 bytes). Wrap the parse in try/catch so a truncated or malformed 409 body
still cancels the send (owner logged as "unknown") — the 409 status itself
means another agent owns this thread, independent of body parseability.

The discord webhook and huggingface /v1/models success reads from the original
PR were superseded upstream by openclaw#98098 and openclaw#101079 (readProviderJsonResponse),
so this branch now carries only the thread-ownership fix.

Co-Authored-By: Claude <[email protected]>
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 14, 2026
…mantics

The thread-ownership 409 conflict path still used unbounded resp.json(),
inconsistent with the bounded readers shipped across the other channel/provider
success paths. A compromised or buggy forwarder returning a multi-GB 409 body
would buffer the entire body before JSON.parse, OOMing the agent.

Bound the 409 body via readResponseTextLimited (8 KiB cap; a 409 owner field is
~30 bytes). Wrap the parse in try/catch so a truncated or malformed 409 body
still cancels the send (owner logged as "unknown") — the 409 status itself
means another agent owns this thread, independent of body parseability.

The discord webhook and huggingface /v1/models success reads from the original
PR were superseded upstream by openclaw#98098 and openclaw#101079 (readProviderJsonResponse),
so this branch now carries only the thread-ownership fix.

Co-Authored-By: Claude <[email protected]>
steipete pushed a commit that referenced this pull request Jul 18, 2026
…mantics (#98941)

* fix(thread-ownership): bound 409 response read and preserve cancel semantics

The thread-ownership 409 conflict path still used unbounded resp.json(),
inconsistent with the bounded readers shipped across the other channel/provider
success paths. A compromised or buggy forwarder returning a multi-GB 409 body
would buffer the entire body before JSON.parse, OOMing the agent.

Bound the 409 body via readResponseTextLimited (8 KiB cap; a 409 owner field is
~30 bytes). Wrap the parse in try/catch so a truncated or malformed 409 body
still cancels the send (owner logged as "unknown") — the 409 status itself
means another agent owns this thread, independent of body parseability.

The discord webhook and huggingface /v1/models success reads from the original
PR were superseded upstream by #98098 and #101079 (readProviderJsonResponse),
so this branch now carries only the thread-ownership fix.

Co-Authored-By: Claude <[email protected]>

* fix(thread-ownership): bound forwarder conflict handling

---------

Co-authored-by: Claude <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 19, 2026
…mantics (openclaw#98941)

* fix(thread-ownership): bound 409 response read and preserve cancel semantics

The thread-ownership 409 conflict path still used unbounded resp.json(),
inconsistent with the bounded readers shipped across the other channel/provider
success paths. A compromised or buggy forwarder returning a multi-GB 409 body
would buffer the entire body before JSON.parse, OOMing the agent.

Bound the 409 body via readResponseTextLimited (8 KiB cap; a 409 owner field is
~30 bytes). Wrap the parse in try/catch so a truncated or malformed 409 body
still cancels the send (owner logged as "unknown") — the 409 status itself
means another agent owns this thread, independent of body parseability.

The discord webhook and huggingface /v1/models success reads from the original
PR were superseded upstream by openclaw#98098 and openclaw#101079 (readProviderJsonResponse),
so this branch now carries only the thread-ownership fix.

Co-Authored-By: Claude <[email protected]>

* fix(thread-ownership): bound forwarder conflict handling

---------

Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord extensions: openrouter merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants