Skip to content

fix(prep-fused): 리뷰 결함 12건 수정 + PR #224 가 되돌린 EXP-7 복원 (v2, 기본 off) - #226

Merged
choiceoh merged 4 commits into
mainfrom
feat/glm53-prep-fused-v2
Sep 2, 2026
Merged

fix(prep-fused): 리뷰 결함 12건 수정 + PR #224 가 되돌린 EXP-7 복원 (v2, 기본 off)#226
choiceoh merged 4 commits into
mainfrom
feat/glm53-prep-fused-v2

Conversation

@choiceoh

@choiceoh choiceoh commented Sep 2, 2026

Copy link
Copy Markdown
Owner

왜 이 PR 인가

확인된 결함과 수정 (전부 검증 CONFIRMED, 상세는 MEASUREMENTS.md EXP-7 리뷰 항목)

  1. UVA 핸들 stale: plan 이 prefill_len.gpu / num_blocks.gpu 를 캐시했는데 둘은 copy_to_uva() 마다 다른 풀 버퍼로 재바인딩됩니다 (num_blocks 는 매 스텝 회전). 격 스텝마다 stale → 새 블록으로 넘어가는 스텝의 gather 가 한 블록 짧아 어텐션이 잘못된 블록을 읽음 (이미지 코드로 재현). → 발사 시점에 소유 객체에서 읽음.
  2. 드래프터 그룹 빌더: 7번째 KV 그룹에 타깃 쪽 FlashInfer 빌더가 붙어 있어 build_plan 이 모든 실제 부팅에서 실패, 모듈 inert. → 레이어 소속으로 식별.
  3. pinned 스테이징 경합 (async scheduling 아래, GB10 재현) → 이미지의 UvaBufferPool.
  4. Q 2의 거듭제곱 가드·warmup 실패·발사 예외: 첫 적격 스텝에서 엔진 사망 가능 → 가드 + DISARM + stock 폴백.
  5. shadow 가 armed 분기를 실행 안 함 → 검증 뒤 fused 배치를 흘리고 armed 도 64 스텝마다 self-check (drift 면 DISARM).
  6. kpool tail 휴면 가정 → plan·검증마다 assert. 7. 메타데이터 캐시 안전성 → speculator 타입 게이트. 8. 노브 오타 arm → 미지 값 DISARM.
  7. 문서의 EXTRA_ENV= 명령이 런처에서 ABORT (프로필 선언 키; EXP-6 도 동일) → caller env 형식 + 문서 lint 테스트.
  8. 프로브 래퍼가 preimage 검증 없이 마운트 → 런처와 같은 검증, 프로필 이미지 기본.
  9. "88/64 us GPU" 는 호스트 발사 시간 (실제 커널 ~23 us) → 원장·README 정정, 하네스는 CUDA 그래프 리플레이로 GPU 시간 측정.
  10. warmup 의 컴파일 커널로 직접 발사 (호스트 ~12 us/스텝 절감), _load_ptr·PAD_SLOT_ID 재사용, 행 복사 2D 브로드캐스트, 와이어링 훅의 ImportError 구분.

게이트

  • tests/test_logic.py 41,074 checks OK (신규: 문서 EXTRA_ENV lint, v2 계약).
  • 오프라인 (srv2, glm53:v13-b12x, 31개 행 preimage 검증): 무작위 배치 60/60 bit-exact (팔 사이에 UVA 핸들 회전 포함), C=1 스텝당 stock 2,469~2,535 us vs fused 152 us (호스트+GPU), 실제 GPU 24.5 us.
  • 서빙 미측정: VLLM_GLM53_PREP_FUSED=shadow bash launchers/start-glm53-nvfp4-tp4.sh (caller env) 로 섀도 부팅 → drift=0 → EXP-7 브래킷. async-dflash 는 EXP-8 그대로.

🤖 Generated with Claude Code


Note

High Risk
Changes decode-step input/KV metadata on the hot path with bit-exact contracts; async-dflash doubles in-flight KV batches. Both default off and DISARM on drift, but armed mistakes could corrupt attention block tables or serving behavior.

Overview
Restores EXP-7 (glm53_prep_fused) and EXP-8 (glm53_async_dflash) after PR #224 reverted them, and hardens the fused prep path from the post–#221 review.

EXP-7 adds a Triton _glm53_prep_fused_kernel plus runner patches (no file overwrites) that fold uniform spec-verify decode prep into one H2D copy, one kernel launch, and deep_gemm schedule metadata. It is gated by VLLM_GLM53_PREP_FUSED (off / shadow / on), pins 17 runner/builder preimages (drift → DISARM), and enforces bit-exact shadow and periodic self-check with stock fallback. Review fixes include reading live UvaBackedTensor handles at launch (not cached .gpu), correct drafter KV-group detection, UvaBufferPool for idx_mapping under async, power-of-two Q guards, speculator-type gating for metadata cache, invalid env → DISARM, and direct launch of warmup-compiled Triton to cut host dispatch.

EXP-8 ships a pinned glm53_config_vllm.py overlay that whitelists dflash for async scheduling when VLLM_GLM53_ASYNC_DFLASH=1, so dflash boots are no longer forced synchronous by method name alone.

Docs/runbook: new EXP-7/EXP-8 ladders, trace-driven idle analysis in STEP_KERNEL_MAP.md / MEASUREMENTS.md, corrected timing notes (host vs ~24µs GPU), and megakernel/prep env examples switched from EXTRA_ENV= to caller env (launcher aborts profile keys). manifest.tsv adds the new build artifacts; glm5next_model.py imports and installs prep-fused at model init.

Reviewed by Cursor Bugbot for commit 3e7a1d5. Bugbot is set up for automated code reviews on this repo. Configure here.

choiceoh and others added 3 commits September 2, 2026 19:17
…P-7)

9월 1일 트레이스(rank 3, 229 스텝)를 스트림 합집합으로 다시 읽으면 스텝의
12%(8.9 ms/72 ms, 프로파일러 없이 4~5 ms)가 GPU 유휴이고, 그 자리가 드래프터
그래프와 타깃 그래프 사이의 eager 입력 준비다: prepare_inputs + prepare_attn +
KV 그룹 7개의 메타데이터 빌더가 스텝마다 aten ~1,000 호출, memcpy 45, 1~3 us
커널 ~100개를 내고 dflash 는 스케줄러가 동기라 그 시간 내내 GPU 가 빈다.

새 모듈 glm53_prep_fused 는 균일 spec-verify 스텝(전 요청 드래프트 7개, FULL
그래프, 요청 패딩 없음)에서 그 구간 전체를 pinned H2D 1회 + Triton 발사 1회 +
deep_gemm 스케줄 1회로 접는다. 러너 파일은 덮지 않고 메서드를 패치하며, 설치
시 러너/빌더 파일 17개의 preimage 를 고정하고(드리프트 -> DISARM), plan 은
캡처 직후 live 러너에서 만들어 커널을 미리 컴파일한다. 메타데이터 dict 는
형상별 캐시(FULL 리플레이는 버퍼만 읽고, dict 는 드래프터에 넘어가 무시된다).

계약은 stock 버퍼와 bit-exact: shadow 모드는 fused 뒤에 stock 을 같은 버퍼에
돌려 전부 diff 하고 stock 이 진실이다. 오프라인 게이트(srv4 새 컨테이너,
probes/run_prep_fused_check.sh): 프로덕션 기하의 무작위 배치 60/60 이 46개
텐서 bit-exact, C=1 스텝당 빌딩블록 2,556 us -> 201 us(커널 88 + deep_gemm
스케줄 64). 서빙 수치는 없다 -- 섀도 부팅 drift=0 뒤 EXP-7 브래킷.

기본값 0. 부수 발견은 원장에: kpool tail 원형 매핑이 positions 미전달로
잠들어 있음(C>=2 수치 축), 인덱서 fp32 head-gate gemmSN 86 us x 11층,
드래프터 커널 합 ~3 ms 와 D≈0 의 긴장.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 454efe4)
…% (EXP-8, 기본 off)

이미지 config/vllm.py 의 async_scheduling 자동 판정은 speculative method
이름 허용 목록(eagle 계열, ngram GPU, draft_model, dspark)이라 dflash 부팅은
전부 "Async scheduling not supported with dflash-based speculative decoding
and will be disabled" 로 동기 스케줄러를 쓴다. 업스트림 main 도 같다.

기전으로는 이름 문제다: DSparkSpeculator 는 DFlashSpeculator 의 서브클래스로
propose() 를 상속하고(async 가 건드리는 유일한 드래프터 흐름), dspark 는 dsv4
에서 --async-scheduling 으로 서빙 중이며, V2 러너에는 method 별 async 분기가
없다(스케줄러의 [-1] placeholder 를 워커가 combine_sampled_and_draft_tokens
커널로 덮어쓴다). 마운트된 glm53 오버레이 중 스케줄러 쪽 드래프트 id 를 읽는
것은 없다.

새 모듈 glm53_async_dflash 는 플릿 이미지의 config/vllm.py(preimage 2469…)에
hunk 셋: 헬퍼 _deneb_dflash_async_ok(method) 와 두 허용 조건 각각의
`and not _deneb_dflash_async_ok(...)`. 헬퍼는 VLLM_GLM53_ASYNC_DFLASH=1 이고
method 가 dflash 일 때만 True 이며 부팅 로그에 자기 선언. 기본 0 = stock 판정.
파일 전체를 마운트하는 이유는 판정이 프런트엔드·엔진코어 프로세스에서 모델
모듈 import 전에 돌아 우리 훅이 닿지 않기 때문이다.

기대값: 9월 1일 트레이스의 GPU 유휴(입력 준비 ~5.7 + 그래프 제출 1.43 + 스텝
전환 = 스텝의 12%, 프로파일러 없이 ~7%)가 동기 스케줄러가 임계경로에 올린
호스트 시간 전부다 -- 천장 7~12%. glm53_prep_fused 와 독립.

게이트: srv2 의 glm53:v13-b12x 에서 패치 파일 import + 노브 반응 스모크 통과,
tests/test_logic.py 41,037 checks. 서빙 미측정 -- EXP-8: 품질 9/9, 한국어
0/16, pos-1 수용률 ±2pct(움직이면 안 됨), C=1 step/s 브래킷, KV in-flight
예약 2배 확인.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 6949cb2)
PR #221 은 09:46Z 머지됐으나 PR #224(e76452f) 가 언급 없이 18개 파일 변경을
전부 되돌려 main 에서 사라졌다. 이 브랜치는 #221·#223 을 main 위에 다시 올리고
(cherry-pick), 10 관점 리뷰 + 검증 14건에서 확인된 결함을 고친다.

CONFIRMED 결함과 수정:
- plan 이 prefill_len.gpu / num_blocks.gpu 를 캐시: 둘은 UvaBackedTensor 라
  copy_to_uva() 마다 라운드로빈 풀의 다른 버퍼로 재바인딩된다(num_blocks 는
  매 스텝 apply_staged_writes 로 회전). 격 스텝마다 한 스텝 stale -> 새 블록으로
  넘어가는 스텝에 gather 가 한 블록 짧아 어텐션이 잘못된 블록을 읽음. 이미지
  코드로 재현. 수정: 소유 객체(BlockTables, UvaBackedTensor)를 plan 에 두고 발사
  시점에 .gpu / 포인터 텐서를 읽는다(wake-up 재생성도 자동 반영).
- 드래프터 KV 그룹(7번째)에 타깃 쪽 FlashInfer 빌더가 붙어 있어 build_plan 이
  모든 실제 부팅에서 실패 -> 모듈 inert. 수정: 드래프터 그룹을 레이어 소속
  (draft_attn_layer_names / draft_kv_cache_group_ids)으로 식별해 gather+slot 만.
- pinned 스테이징 버퍼 1개 재사용이 async scheduling 아래에서 이전 스텝 DMA 와
  경합(GB10 재현). 수정: 이미지의 UvaBufferPool(동시 배치 수 라운드로빈).
- Q 가 2의 거듭제곱이 아니면 tl.arange 컴파일 실패가 첫 적격 스텝에서 엔진을
  죽임. 수정: plan 가드, warmup 실패 DISARM, 발사 예외 시 stock 폴백.
- shadow 가 stock 배치를 반환해 armed 분기를 한 번도 실행 안 함. 수정: fused 뒤
  stock 사슬 전체(prepare_inputs·gather/slot·빌더)를 돌려 diff 하고 깨끗하면
  fused 배치를 흘린다; armed 도 64 fused 스텝마다 self-check, drift 면 DISARM.
- kpool tail 원형 버퍼 휴면을 가정만 함. 수정: plan 생성·검증마다 assert.
- 메타데이터 캐시는 dflash 가 dict 를 무시할 때만 안전. 수정: speculator 타입 게이트.
- 노브 오타가 arm 으로. 수정: 0/off/false/no, shadow, 1 만 인정, 나머지 DISARM.
- 런북·README 의 EXTRA_ENV="VLLM_GLM53_..." 는 프로필 선언 키라 런처가 ABORT
  (EXP-6 도 동일). 수정: caller env 형식 + 문서 lint 테스트.
- 프로브 래퍼가 preimage 검증 없이 전 행을 마운트(fi618 위에 v13 오버레이 5개).
  수정: 런처와 같은 base contract 검증, 프로필 이미지 기본.
- "88/64 us GPU" 는 호스트 발사 시간(실제 커널 ~23 us). 원장·README 정정, 하네스는
  CUDA 그래프 리플레이로 GPU 시간을 잰다.
- warmup 이 돌려주는 컴파일 커널로 직접 발사(Triton 디스패처 ~12 us/스텝 절감,
  검증에서 bit-exact); _load_ptr·PAD_SLOT_ID 재사용; 행 복사 2D 브로드캐스트;
  와이어링 훅은 "미마운트" 와 "모듈 내부 ImportError" 를 구분해 후자를 로그.

오프라인 게이트(srv2, glm53:v13-b12x, 31개 행 preimage 검증): 무작위 배치 60/60
bit-exact(UVA 핸들 회전 포함), C=1 스텝당 stock 2,469 us vs fused 184 us
(호스트+GPU), 실제 GPU 24.4 us(그래프 리플레이). tests/test_logic.py 통과.
서빙 미측정: EXP-7 섀도 부팅 -> 브래킷.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 2, 2026 10:34
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T11:16:57.445133Z 3e7a1d5 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

_patched_ms_prepare_attn calls st.plan.tail_ok() without handling its RuntimeError, which can crash the engine instead of DISARMing back to stock.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Restores GLM-5.3 EXP-7 (glm53_prep_fused) and EXP-8 (glm53_async_dflash) overlays after an unintended revert, and applies the confirmed post-review fixes to make the optimizations safer (default-off, preimage-pinned, shadow/self-check + DISARM fallbacks).

Changes:

  • Add/restore glm53_prep_fused fused decode-step input-prep (Triton) with preimage pinning, eligibility guards, shadow/self-check verification, and offline numerics probe.
  • Add/restore glm53_async_dflash opt-in allowlisting so dflash can use async scheduling when explicitly enabled.
  • Update profile defaults, manifests, and docs/runbooks/measurements; add logic-contract tests to prevent regressions (incl. EXTRA_ENV lint).
File summaries
File Description
tests/test_logic.py Adds contract tests for prep-fused + async-dflash, and lints docs to avoid EXTRA_ENV for profile-declared keys.
STEP_KERNEL_MAP.md Adds supplemental trace breakdown clarifying host-side idle regions and motivation for EXP-7/8.
RUNBOOK_KERNEL_CAMPAIGN2.md Updates arming instructions (caller env, not EXTRA_ENV) and documents EXP-7/EXP-8 ladders.
profiles/glm53.env Mounts new modules and introduces default-off knobs VLLM_GLM53_PREP_FUSED=0, VLLM_GLM53_ASYNC_DFLASH=0.
probes/run_prep_fused_check.sh Adds wrapper to validate overlay base preimages and run the prep-fused probe in a fresh container.
probes/prep_fused_check.py Adds randomized bit-exact numerics + launch/timing probe for prep-fused vs stock building blocks.
overlay/modules/glm53_prep_fused/requires Declares module dependencies for prep-fused overlay.
overlay/modules/glm53_prep_fused/README.md Documents motivation, behavior, guards, and arming ladder for prep-fused.
overlay/modules/glm53_prep_fused/manifest.tsv Declares prep-fused file mount (new file) for overlay composition.
overlay/modules/glm53_prep_fused/glm53_prep_fused.py Implements the fused prep kernel + runner/model-state patching and verification/disarm logic.
overlay/modules/glm53_model_wiring/glm5next_model.py Imports and conditionally installs prep-fused when module is mounted and knob is set.
overlay/modules/glm53_async_dflash/requires Empty dependency declaration file for async-dflash module.
overlay/modules/glm53_async_dflash/README.md Documents async-dflash rationale, changes, gates, and arming instructions.
overlay/modules/glm53_async_dflash/manifest.tsv Declares full-file mount of vllm/config/vllm.py with pinned preimage.
overlay/modules/glm53_async_dflash/glm53_config_vllm.py Adds _deneb_dflash_async_ok() helper and threads it into both async-scheduling allowlist checks.
MEASUREMENTS.md Records EXP-7/8 findings, corrected host-vs-GPU timing, and v2 gate results.
build/glm53/manifest.tsv Adds composed build rows for prep-fused and async-dflash overlays.
build/glm53/glm5next_model.py Built artifact reflecting the wiring hook for prep-fused install.
build/glm53/glm53_prep_fused.py Built artifact copy of prep-fused implementation.
build/glm53/glm53_config_vllm.py Built artifact copy of async-dflash vllm.py overlay.
Review details
  • Files reviewed: 17/20 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1002 to +1005
md = orig(self, input_batch, cudagraph_mode, block_tables, slot_mappings,
attn_groups, kv_cache_config, for_capture)
st.plan.tail_ok()
st.metadata_cache[key] = md
Comment on lines +1002 to +1005
md = orig(self, input_batch, cudagraph_mode, block_tables, slot_mappings,
attn_groups, kv_cache_config, for_capture)
st.plan.tail_ok()
st.metadata_cache[key] = md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a75da2af9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +968 to +969
if st.mode != "shadow":
st.disarm("self-check drift")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Disarm shadow mode after detecting drift

When shadow mode detects a mismatch, it returns the stock batch only for the current step but deliberately avoids st.disarm(). If VLLM_GLM53_PREP_FUSED_SHADOW_EVERY is greater than 1, the intervening unchecked steps then resume serving the already-known-bad fused path via the if not check: return fused branch, which can corrupt shadow experiment results. A detected drift should disable the fused path for shadow mode as well.

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4a75da2. Configure here.

Comment thread overlay/modules/glm53_prep_fused/glm53_prep_fused.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not approved: Cursor Bugbot ended as skipped after the wait window and left one unresolved high-severity finding that needs human review. Reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

리뷰 스윕 지적: tail 그룹 폭 8/행당 블록 1개인데 position 이 ~5000 까지 가서
stock·fused 양쪽이 표 밖 메모리를 읽고 같은 쓰레기를 비교하고 있었다.
프로덕션처럼 그룹마다 cdiv(max_seq, block) 이상을 할당한다.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: Cursor Bugbot passed on the current head with no unresolved findings that need human review. No reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e7a1d5d6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# them live, but the cached metadata dicts hold views -> rebuild
st.plan = None
st.metadata_cache.clear()
st.plan_failed = False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve DISARM across KV-cache wake-up

When an armed self-check drift or fused-launch failure has called st.disarm(), a later sleep-mode KV-cache wake reaches this hook and unconditionally clears plan_failed. The next eligible decode step therefore rebuilds the plan and resumes the known-bad fused path, despite disarm() promising stock behavior for the rest of the boot. Keep the failure state sticky and only invalidate/rebuild plans that were still armed before the wake.

Useful? React with 👍 / 👎.

@choiceoh
choiceoh merged commit 0e46819 into main Sep 2, 2026
3 checks passed
choiceoh pushed a commit that referenced this pull request Sep 2, 2026
…라운드는 유지

#230 의 커밋(7a287e0)은 0bd06b7 에서 갈라졌으면서 glm53_prep_fused·glm53_async_dflash·
glm53_indexer_gate_splitk 모듈, probes/tools 5개, glm5next_model.py 의 prep-fused 훅,
프로필 MODULES/노브, 테스트 419줄, 원장·RUNBOOK·커널맵 항목을 삭제했다(#224 와 같은
패턴: 오래된 작업 트리로 add -A). 유지한 것 = #230 이 실제로 작성한 것: 메가커널
.cu/README(KDA 2라운드), 테스트의 KDA 계약 2 hunk, 원장 10차 항목. 나머지는 이 브랜치
(0bd06b7 + 리뷰 처리분) 그대로. 41,247 checks OK.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants