Skip to content

Commit ae32007

Browse files
authored
[rustjava-adopt-ldc-tags-real-world-generator-survey-p1] test(survey): kotlinc·scalac 를 타깃 형상으로 몰아 「기능 단위」 0 을 잰다 [rustjava-adopt-ldc-tags-real-world-generator-survey-p1-fix] (#65)
[rustjava-adopt-ldc-tags-real-world-generator-survey-p1] test(survey): kotlinc·scalac 를 타깃 형상으로 몰아 「기능 단위」 0 을 잰다 [rustjava-adopt-ldc-tags-real-world-generator-survey-p1-fix]
2 parents f19acf7 + a28f6cb commit ae32007

7 files changed

Lines changed: 253 additions & 0 deletions

File tree

‎REPORT.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@
118118
- ★★**잃는 것 — 기각은 공짜가 아니다**: 생성기 머리의 `These are **synthetic**` 단서가 양성 픽스처에도 남고, ★**우리 인코더의 체계적 편향을 우리 파서«와» OpenJDK 가 «둘 다» 관대하게 넘기는 경우**는 ASM 이라면 드러났을 것이다(JVM 검증기는 **센 필터이지 증명이 아니다**). 어느 쪽이든 «현실성»의 상시 보장은 없다.
119119
- ★후속: 더 싼 대안을 카드로 남겼다 — **재생성 대신 양성 픽스처를 진짜 JVM 에 올려 현실성 검사로 삼는다**(선례 `verify-javac-fixtures.sh`) · `docs/worklog/2026-09-17-ldc-asm-regeneration-declined.json`.
120120

121+
## [2026-09-17] kotlinc·scalac 를 «타깃 형상»으로 몰았다 — ★**0. 그러나 «다른 0»** (rustjava-adopt-ldc-tags-real-world-generator-survey-p1)
122+
- 무엇을: 채택 제안 `2026-09-16-ldc-tags-real-world-generator-survey#p1`. 조사 회차가 자기 표에 **「못 쟀다」**로 적어 둔 칸을 채웠다. ★**제품 Rust 0줄**(조사 입력 2 + 스캐너 docstring).
123+
- 왜: 종전 축은 **컴파일러의 stdlib**(= 그 컴파일러 산출물)이었다. ★**stdlib 은 호환성을 위해 컴파일되지 백엔드를 훑으려고 컴파일되지 않는다** — 그래서 「이 코퍼스에서 0」과 「이 기능들에서 0」이 다르다.
124+
- ★**결과**: kotlinc **2.4.20** → 7클래스·23 ldc 자리 · ★**피연산자 15/16/17 = 0** / scalac **3.9.0** → 7·18 · ★**0**.
125+
★★**풀 수치가 이 0 을 읽을 값으로 만든다** — Kotlin `MethodHandle 7 · MethodType 6` · Scala `11 · 6` **(0 이 아니다)** ⇒ ★**indy 경로가 실제로 돌았고 상수도 만들어졌는데 `ldc` 자리에 «닿지 않는다»**. 「안 썼다」가 아니라 「썼는데 안 온다」다.
126+
★**태그 17(Dynamic)은 풀에도 0** ⇒ ★**이 형상들에서는 두 컴파일러 모두 condy 를 내지 않는다**(둘 중 더 센 진술 · ★한정은 나머지 수와 «같다» — **컴파일러당 프로그램 1개**라 기능을 한정하지 언어를 한정하지 않는다).
127+
- ★**타깃 형상**: 람다 · 언바운드/바운드 메서드 참조 · SAM 변환(네이티브+Java 둘 다) · enum 주어 · 문자열 연결 · lazy · (Kotlin) reified · (Scala) eta 확장·inline def·구조적 타입. ★**플래그도 «더 많이» indy 로 보내는 쪽으로 골랐다**(`-Xlambdas=indy`·`-Xsam-conversions=indy`·`-Xstring-concat=indy-with-constants` · `scalac -release 21`).
128+
- ★**양방향**: 같은 스캐너·같은 세션에서 **양성 대조군** `test-data/ldc` → `{MethodHandle 1, MethodType 2, Dynamic 7}` ⇒ ★**이 0 은 「스캐너가 못 본다」가 아니다.** 오차 막대(불가능 피연산자) 두 실행 **0.00%**.
129+
- ★**제안의 값 전제를 다시 재서 «부분적으로 거짓»임을 찾았다**: 「JVM 툴체인이 의도적으로 없는 맥」이라 했으나 ★**openjdk 26 은 2026-07-22 부터 설치돼 있었다**(`INSTALL_RECEIPT` 의 **`time`** 필드 = epoch `1784711495` · KST 18:11:35 — ★**`source_modified_time`(=formula 최종 수정)이 아니다**)(조사 회차 **09-16** 보다 **56일**, 약 2개월 앞선다) ⇒ 한계 설치는 **formula 하나씩**이었다 — ★**단 «하나씩»이 공짜는 아니다**: 그 의존 해결이 위 **openjdk 판본 승격을 동반**했다(대가 절).
130+
- ★★**대가**: **머신 상태가 바뀌었다** — `kotlin 2.4.20`·`scala 3.9.0`(+`scala-cli`) 설치 · ★**그리고 «신고에서 빠져 있던» 한 가지 — `openjdk` 기본 링크가 «의존성으로» 26.0.1 → 26.0.2.1 로 승격됐다**(`/opt/homebrew/opt/openjdk` · 같은 순간 `time 2026-09-17T12:48:50Z` · `installed_on_request false`). ★**되돌리기**: `brew uninstall kotlin scala` 는 **이 링크를 되돌리지 않는다**. 그리고 ★**Homebrew 7 에는 판본을 되돌릴 명령이 없다**(`brew switch` 제거). 실효 처방은 ★**26.0.1 keg 가 그대로 있으므로 소비자가 경로를 핀하는 것**이다 — `JAVA_HOME=/opt/homebrew/Cellar/openjdk/26.0.1`(실행 확인: `java -version` → `26.0.1`). ★**범위**: openjdk 는 **keg-only** 라 `PATH` 의 `java` 는 `/usr/bin/java` 로 **안 바뀐다** — 영향은 `/opt/homebrew/opt/openjdk` 를 **명시적으로** 쓰는 소비자(이 회차가 그랬다)뿐이다. 레인 약 28개가 공유하는 맥이고, **가산적·가역**(`brew uninstall kotlin scala`)이라 **재측정 가능성을 위해 일부러 남겼다**. ★컴파일러당 프로그램 «하나»라 **기능**을 한정할 뿐 **언어**를 한정하지 않는다. ★**CI 에서 못 돈다**(`setup-java` 0건) — 사람이 돌리는 검사다.
131+
- ★**답은 제안이 예상한 그 0 이다** — 산 것은 **오차 막대**뿐이고, 그것이 이 회차 값의 정직한 회계다.
132+
121133
## [2026-09-17] base 를 당겼다 — ★**막고 있던 코드 충돌은 «이미 없었다»**(rustjava-adopt-link-stringconcatfactory-p1-fix2)
122134
- 무엇을: `origin/main` 당김(뒤처짐 **9**) + 그 당김이 만든 `test-data/class-file-versions.txt` **3행**. ★제품 코드 **0줄** · 픽스처 바이트 **불변**.
123135
- ★★**전제가 반증됐다**: 이 회차는 「`make_indy_fixtures.py` 4구역 코드 충돌」을 풀라고 발권됐는데, 지금 당기면 그 파일은 **충돌하지 않는다**. `-p1-fix` 회차가 **14:10 에 `0f06b93f` 로 이미 합집합 해소**했고 게이트②가 **15:43 에 그 head 를 approve** 했다 — 발권 근거였던 12:12 blocked 회신이 그 사이 **낡았다**.

‎STATE.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@
8585
게이트② **approve** · 핀 **`c0413f81`** ↔ 착수 시 PR head **동일**(불이동) · ★**`MERGEABLE/CLEAN` · base 뒤처짐 «0»** ⇒ 충돌 해소·base 당김 **둘 다 불요**.
8686
★핀에서 `ci-presence` **rc=0 CI_GREEN** · 자식 PR **0건** · 배포 **0**(배포 워크플로 없음) · 주기 자동 커밋 **0건** · 라이브 실행 주체 **없음**.
8787
★★**착지시킨 것은 «기각 기록»이다** — 제품 코드 **0줄**이 정상이고, 착지 diff 는 원장 4파일뿐이다.
88+
- [rustjava-adopt-ldc-tags-real-world-generator-survey-p1] ★★**kotlinc·scalac 타깃 형상 조사 — 0. 그러나 «다른 0».** 채택 제안 `…-survey#p1`(worklog json `adoptedProposals` 기록) · ★**제품 Rust 0줄**.
89+
★조사 회차가 **「못 쟀다」로 비워 둔 칸**을 채웠다 — 종전 축은 stdlib(호환성용 컴파일)이라 「이 코퍼스에서 0」과 「이 기능들에서 0」이 달랐다.
90+
★**kotlinc 2.4.20 → 0 · scalac 3.9.0 → 0**. ★★**풀 수치가 그 0 을 읽을 값으로 만든다**(Kotlin `MH 7·MT 6` · Scala `11·6` = **indy 가 실제로 돌았다**) ⇒ 「안 썼다」가 아니라 **「썼는데 `ldc` 자리에 안 온다」**.
91+
★**태그 17 은 풀에도 0** ⇒ ★**이 형상들에서는** 두 컴파일러 다 **condy 를 안 낸다**(한정은 나머지 수와 같다 — 컴파일러당 프로그램 1개).
92+
★**양방향**: 양성 대조군 `test-data/ldc` → `{MH 1, MT 2, Dynamic 7}` ⇒ 「스캐너가 못 본다」 배제 · 오차막대 **0.00%**.
93+
★**제안의 값 전제가 부분적으로 거짓**이었다 — openjdk 26 은 **2026-07-22 부터** 설치돼 있었다(`INSTALL_RECEIPT` **`time`** = `1784711495` · ★`source_modified_time` 아님) — 조사(09-16)보다 **56일** 전.
94+
★★**대가**: 머신에 `kotlin`·`scala` **설치됨**(재측정 위해 남겼다) · ★**추가 신고 — `openjdk` 기본 링크 26.0.1 → 26.0.2.1 승격**(의존성 · `/opt/homebrew/opt/openjdk`).
95+
★`brew uninstall kotlin scala` 로는 **안 돌아온다**(Homebrew 7 은 `brew switch` 없음) ⇒ 처방은 **26.0.1 keg 경로 핀**(`JAVA_HOME=/opt/homebrew/Cellar/openjdk/26.0.1` · 실행 확인). ★keg-only 라 `PATH` 의 `java`(=`/usr/bin/java`)는 **불변** — 영향은 opt 경로를 명시적으로 쓰는 소비자뿐.
96+
★컴파일러당 프로그램 1개 · **CI 불가**.
8897
- [rustjava-adopt-link-stringconcatfactory-p1-fix2] ★★**base 당김 — 그런데 막고 있던 코드 충돌은 «이미 없었다»(PR #60).**
8998
★**전제 반증**: 「`make_indy_fixtures.py` 4구역 충돌」은 `-p1-fix` 가 **14:10 `0f06b93f`** 로 합집합 해소했고 게이트②가 **15:43 그 head 를 approve** 했다.
9099
발권 근거(12:12 blocked 회신)가 그 사이 낡은 것이다. ★**재발 불가**도 확인 — 뒤진 9커밋 중 그 파일을 만진 것 **0건**.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"schema": "worklog/v1",
3+
"date": "2026-09-17",
4+
"taskId": "rustjava-adopt-ldc-tags-real-world-generator-survey-p1",
5+
"summary": "Adopted: drove kotlinc and scalac over targeted source shapes instead of only their stdlib output, closing the gap the survey named about itself. Result is the same zero the proposal expected — but it is now a zero about features rather than about one corpus, and the constant pool counts prove the invokedynamic paths were actually exercised. Tag 17 (Dynamic) is absent from the pool entirely in both compilers, which is the stronger finding: in these shapes neither emits condy at all (one program per compiler, so it bounds the listed features and not the languages).",
6+
"changes": [
7+
"scripts/ldc-tag-survey-targets/Targets.kt: Kotlin shapes — lambda, unbound and bound callable references, SAM conversion to a Kotlin fun interface and to a Java interface, enum `when`, string templates, lazy delegate, reified type parameter",
8+
"scripts/ldc-tag-survey-targets/Targets.scala: Scala 3 shapes — lambda, eta-expansion, SAM conversion to a Scala trait and to a Java interface, enum match, string interpolation, lazy val, inline def, structural type",
9+
"scripts/survey-ldc-constant-tags.py: docstring records the commands, the compiler versions, the numbers, the positive control and what the measurement does not cover"
10+
],
11+
"verification": [
12+
"kotlinc-jvm 2.4.20 (JRE 26): 7 classes / 23 ldc sites / tags 15,16,17 as an ldc operand: 0; same tags in the pool: MethodHandle 7, MethodType 6",
13+
"Scala 3.9.0: 7 classes / 18 ldc sites / tags 15,16,17 as an ldc operand: 0; same tags in the pool: MethodHandle 11, MethodType 6",
14+
"the pool counts are the non-vacuity check: they are non-zero, so the invokedynamic machinery really ran and the handles/types really were built — they simply never reach an ldc operand",
15+
"tag 17 (Dynamic) is 0 in the pool as well as at ldc sites for both compilers, so in these shapes neither emits condy at all — bounded like every other number here: one program per compiler, which bounds the listed features and not the languages",
16+
"POSITIVE CONTROL, same scanner, same session: `python3 scripts/survey-ldc-constant-tags.py test-data/ldc` -> {MethodHandle 1, MethodType 2, Dynamic 7}. So the 0 above is not 'the scanner cannot see these tags'.",
17+
"scanner error bar on both targeted runs: impossible operands 0 (0.00%)",
18+
"flags chosen to route *more* through invokedynamic (-Xlambdas=indy, -Xsam-conversions=indy, -Xstring-concat=indy-with-constants; scalac -release 21). Measuring without them would test a compiler configured away from the question.",
19+
"cargo test --all: 578 passed / 0 failed / 1 ignored — unchanged, this round adds no Rust",
20+
"the proposal's cost premise was re-measured and is partly false: it says the machine is 'deliberately kept free of JVM toolchains', but openjdk 26 has been installed via homebrew since 2026-07-22 (INSTALL_RECEIPT field `time` = 1784711495; not `source_modified_time` = 1773157346, which is when the formula was last edited), 56 days before the survey. The marginal install was therefore one formula each: brew deps are kotlin->openjdk, scala->openjdk+scala-cli."
21+
],
22+
"issues": [
23+
"MACHINE STATE CHANGED: kotlin 2.4.20 and scala 3.9.0 (plus scala-cli) are now installed via homebrew on a machine shared by ~28 agent lanes. Additive, and left in place deliberately. A second change went unreported in the first draft: resolving those dependencies also promoted the default `openjdk` link from 26.0.1 to 26.0.2.1 (/opt/homebrew/opt/openjdk, installed_on_request false). `brew uninstall kotlin scala` does NOT undo that, and Homebrew 7 has no command that does (`brew switch` was removed). The working remedy is to pin the consumer rather than the machine: JAVA_HOME=/opt/homebrew/Cellar/openjdk/26.0.1, verified by running it. Scope: openjdk is keg-only, so PATH `java` is still /usr/bin/java and did not change — only consumers that name /opt/homebrew/opt/openjdk explicitly (this round did) see the promotion. Reverting the global symlink by hand is mechanically possible but was not done — and left in place deliberately so the measurement can be re-run, but it is a change nobody else asked for.",
24+
"One program per compiler. This bounds the listed features, not the languages — the survey's own framing of the corpus axis applies here in the other direction.",
25+
"Not runnable in CI: no setup-java step exists, and now two more compilers would be needed. Like test-data/src/verify-javac-fixtures.sh this is a check a person runs.",
26+
"The answer is the same zero the proposal predicted. What was bought is the error bar, exactly as its tradeoff said — and that is the honest accounting of the round's value."
27+
],
28+
"adoptedProposals": [
29+
"2026-09-16-ldc-tags-real-world-generator-survey#p1"
30+
],
31+
"proposals": []
32+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# 2026-09-17 — kotlinc·scalac 를 «타깃 형상»으로 몰았다 (rustjava-adopt-ldc-tags-real-world-generator-survey-p1)
2+
3+
채택 제안 `2026-09-16-ldc-tags-real-world-generator-survey#p1`.
4+
조사 회차는 **컴파일러의 stdlib**(= 그 컴파일러 자신의 산출물)을 쟀고, ★**「그 컴파일러에게 «문제의 기능»을
5+
직접 컴파일시키지는 않았다」를 자기 표에 「못 쟀다」로 적어 두었다.** 그 칸을 채운다.
6+
7+
## 결과 — ★**0. 그러나 «다른 0» 이다**
8+
9+
| 컴파일러 | 버전 | 클래스 | ldc 자리 | ★**ldc 피연산자 15/16/17** | 풀에 «존재» |
10+
|---|---|---|---|---|---|
11+
| Kotlin | kotlinc-jvm **2.4.20** (JRE 26) | 7 | 23 | ★**0** | MethodHandle **7** · MethodType **6** |
12+
| Scala 3 | scalac **3.9.0** | 7 | 18 | ★**0** | MethodHandle **11** · MethodType **6** |
13+
14+
★★**풀 수치가 이 0 을 읽을 값으로 만든다** — 0 이 아니다. 즉 **indy 경로가 실제로 돌았고 상수도 실제로 만들어졌다.**
15+
다만 그것들이 **`ldc` 피연산자에 닿지 않는다.** ⇒ 「안 썼다」가 아니라 ★**「썼는데도 그 자리에 안 온다」**이다.
16+
17+
★**태그 17(Dynamic)은 풀에도 0** 이다 — ⇒ ★**이 형상들에서는 두 컴파일러 모두 condy 를 내지 않는다.** 둘 중 더 센 진술이고,
18+
★**한정은 이 문서의 나머지 수와 «같다»** — 컴파일러당 프로그램 **1개**라 위에 나열한 **기능**을 한정할 뿐 **언어**를 한정하지 않는다.
19+
20+
## 무엇을 «타깃 형상»으로 골랐나
21+
22+
두 파일(`scripts/ldc-tag-survey-targets/Targets.{kt,scala}`) — 태그 15·16 이 컴파일러 산출물에서
23+
**사는 유일한 자리**가 invokedynamic 이므로, **indy 로 가는 기능을 전부** 넣었다:
24+
25+
람다 · **언바운드/바운드 메서드 참조** · SAM 변환(**네이티브 인터페이스 + Java 인터페이스 둘 다**) ·
26+
enum 주어(`when`/`match`) · 문자열 연결 · lazy · (Kotlin) reified 타입 파라미터 · (Scala) **eta 확장 · inline def · 구조적 타입**.
27+
28+
★**플래그도 «더 많이» indy 로 보내는 쪽으로 골랐다**:
29+
```
30+
kotlinc -jvm-target 21 -Xlambdas=indy -Xsam-conversions=indy -Xstring-concat=indy-with-constants -d <out> …/Targets.kt
31+
scalac -release 21 -d <out> …/Targets.scala
32+
python3 scripts/survey-ldc-constant-tags.py <out>
33+
```
34+
★**이 플래그를 빼고 재면 「질문에서 비껴 설정된 컴파일러」를 재는 것**이고, 그것이 코퍼스 축이 피할 수 없던 약점이다
35+
(stdlib 은 **호환성**을 위해 컴파일되지 백엔드를 훑으려고 컴파일되지 않는다).
36+
37+
## ★양방향 — 이 0 이 「스캐너가 못 본다」가 아님을 먼저 보였다
38+
39+
```
40+
python3 scripts/survey-ldc-constant-tags.py test-data/ldc
41+
★ tags 15/16/17 as an ldc operand: {'MethodHandle': 1, 'MethodType': 2, 'Dynamic': 7}
42+
```
43+
같은 스캐너 · 같은 세션에서 **우리 픽스처는 «보인다»** ↔ **타깃 형상은 0**.
44+
스캐너 오차 막대(불가능 피연산자)는 두 타깃 실행 모두 **0 (0.00%)**.
45+
46+
## ★제안의 «값» 전제를 다시 쟀다 — 부분적으로 거짓이었다
47+
48+
제안의 `tradeoff` 는 「**JVM 툴체인이 의도적으로 없는 맥**에 컴파일러 둘을 설치하는 값」이라 했다.
49+
실측: ★**openjdk 26 은 2026-07-22 부터 homebrew 로 설치돼 있었다**(`INSTALL_RECEIPT` 의 **`time`** 필드 =
50+
epoch `1784711495` = 2026-07-22T09:11:35Z = KST 18:11:35) — 조사 회차(**09-16**)보다 **56일**(약 2개월) 앞선다.
51+
★**초판의 날짜는 같은 receipt 의 «다른 필드»에서 왔다** — `source_modified_time`(= `1773157346` = formula 가
52+
마지막으로 수정된 시각 · UTC 2026-03-10T15:42:26Z)을 **로컬(KST)로 환산한 값**이다. ★**날짜는 그 필드에서,
53+
epoch 는 `time` 에서** 가져와 한 문장에 붙였기 때문에 **인용한 수가 그 문장을 스스로 반증**했다.
54+
⇒ 그래서 위 문장은 **어느 필드인지**를 함께 적는다(같은 혼동의 재발 방지가 이 한정의 목적이다). ⇒ 한계 설치 비용은 **formula 하나씩**이었다
55+
(`kotlin → openjdk` · `scala → openjdk, scala-cli`).
56+
57+
## ★대가 — 숨기지 않는다
58+
59+
- ★★**머신 상태가 바뀌었다**: `kotlin 2.4.20` · `scala 3.9.0`(+`scala-cli`)이 **설치됐다**.
60+
에이전트 레인 약 28개가 공유하는 맥이다. ★**일부러 남겼다**(재측정 가능성). **아무도 따로 요청하지 않은 변경**이라 여기 적는다.
61+
- ★★**그리고 초판이 빠뜨린 것 하나 — `openjdk` 기본 링크가 승격됐다**: `26.0.1 → 26.0.2.1`
62+
(`/opt/homebrew/opt/openjdk` · `INSTALL_RECEIPT.time 2026-09-17T12:48:50Z` · `installed_on_request false` = **의존성으로** 들어왔다).
63+
★**초판의 되돌리기 레시피(`brew uninstall kotlin scala`)는 이 링크를 되돌리지 «않는다».**
64+
★**그리고 Homebrew 7.0.3 에는 판본을 되돌리는 명령이 없다** — `brew switch` 는 제거됐다(실측: 미지원 명령).
65+
⇒ ★**실효 처방은 «전역 되돌리기»가 아니라 «소비자 핀»이다**: 26.0.1 keg 가 **그대로 있으므로**
66+
`JAVA_HOME=/opt/homebrew/Cellar/openjdk/26.0.1` 로 고정하면 된다(★**실행 확인** — 그 경로의 `java -version` = `26.0.1`).
67+
★**전역 `opt` 심링크를 손으로 되돌리는 것(`ln -sfn`)도 기전상 가능하지만 이 회차는 «치지 않았다»** —
68+
28레인 공유 머신의 전역 상태이고, brew 가 다음 `link`/`upgrade` 때 다시 옮긴다(기전만 스크래치 심링크로 확인).
69+
★**범위를 정확히**: openjdk 는 **keg-only** 라 `/opt/homebrew/bin` 에 링크되지 않는다 ⇒ `PATH` 의 `java` 는
70+
여전히 `/usr/bin/java` 이고 **바뀌지 않았다**. 영향은 `/opt/homebrew/opt/openjdk` 를 **명시적으로** 쓰는 소비자
71+
(`JAVA_HOME` 지정 등 — **이 회차가 바로 그랬다**)뿐이다.
72+
- **컴파일러당 프로그램 «하나»** ⇒ 위에 나열한 **기능들**을 한정할 뿐 **언어**를 한정하지 않는다.
73+
- ★**CI 에서 못 돈다** — `setup-java` **0건**인데 이제 컴파일러가 둘 더 필요하다.
74+
`test-data/src/verify-javac-fixtures.sh` 와 같은 계급: **사람이 돌리는 검사**다.
75+
- ★**답은 제안이 예상한 그 0 이다.** 산 것은 **오차 막대**뿐이고, 그것이 이 회차 값의 정직한 회계다.

0 commit comments

Comments
 (0)