tooling: rokit → mise 전환 + selene 린터 도입 (roblox-project-example 벤치마킹)
Word30210/roblox-project-example(initreq/에 클론)를 참고해 두 가지 채택: (1) rokit.toml → mise.toml — mise install이 pesde/rojo/luau-lsp/selene을 GitHub attestation+SLSA provenance 검증까지 거쳐 설치하는 걸 이 샌드박스 에서 직접 확인(rokit은 끝내 검증 불가), 이 환경 자체가 이미 mise로 luau를 관리 중이라 더 자연스러움. (2) selene 린터 — 참고 레포의 selene.toml을 패키지별로 채택, 단 CWD 상대 config 탐색 함정을 발견 (루트 단일 설정으로 두면 다른 디렉토리에서 실행 시 조용히 Lua 5.1 std로 폴백해 Luau 타입 문법 전체가 파싱 에러로 잘못 보임) — 참고 레포 그대로 패키지별 selene.toml + 패키지 안에서 실행하는 걸로 확정. 도입 즉시 smoke.mock.luau의 assert 메시지 누락 3건을 잡아 수정. darklua의 convert_require 변환은 검토 후 기각 — 사용자 판단: Roblox 엔진 자체도 이미 같은 require-by-string 의미론(@self/@game)을 지원해 변환 계층이 불필요. Co-authored-by: qwreey <me@qwreey.moe>
This commit is contained in:
parent
2de2f99cc4
commit
ef3d952dd4
9 changed files with 226 additions and 31 deletions
|
|
@ -44,7 +44,7 @@
|
|||
| 문서 | 내용 |
|
||||
|---|---|
|
||||
| `architecture.md` | quad-v2 전체 아키텍처 확정 사항 요약(제일 먼저 볼 문서). **[2026-08-12 세션 신설, 같은 날 후속 세션에서 강화]** "코드 스타일 — Luau 문법 관례" 절 신설 — `if-then-else`가 공식 Luau 문법임을 명문화(환각/오타로 오인해 `and`/`or`로 되돌리는 회귀 방지), `A and B or C` 삼항 관용구는 항상-truthy 예외도 없이 전면 금지로 강화(`bind-system-plan.md`의 `retractUnder` falsy-값 버그가 실사례). `const` 바인딩은 공식 문법이나 툴링 미성숙으로 지금은 채택 보류. **[2026-08-19 정정]** 패키징 매니저를 wally에서 pesde로 전환 — 세부는 `project-setup-plan.md` |
|
||||
| `project-setup-plan.md` | **[2026-08-19 신설]** M0/M1 스캐폴딩을 실제로 pesde/`luau` CLI로 굴려보고 검증한 결과 — pesde 워크스페이스 구조(`workspace_members`, 패키지 이름은 하이픈 금지), `rokit.toml` 툴체인 핀(실제 설치·버전 일치 확인), `init.luau`에서 `@self`가 필수인 이유(Luau RFC `abstract-module-paths-and-init-dot-luau`), 워크스페이스 의존성이 심볼릭 링크로 연결되고 `luau` CLI의 require-by-string이 심볼릭 링크를 안 따라가는 실측 함정과 우회, `.luaurc` alias 런타임 미지원 재확인, `pesde.lock` 커밋 권고(잠정). "확인 완료/아직 확인 안 된 것" 절이 다음에 뭘 검증해야 하는지의 소스 |
|
||||
| `project-setup-plan.md` | **[2026-08-19 신설, 같은 날 두 차례 후속 갱신]** M0/M1 스캐폴딩을 실제로 pesde/`luau`/Rojo/`selene` CLI로 굴려보고 검증한 결과 — pesde 워크스페이스 구조(`workspace_members`, 패키지 이름은 하이픈 금지), `mise.toml` 툴체인 핀(`rokit.toml`에서 전환, 실제 설치·attestation 검증까지 확인), `init.luau`에서 `@self`가 필수인 이유(Luau RFC `abstract-module-paths-and-init-dot-luau`), 워크스페이스 의존성이 심볼릭 링크로 연결되고 `luau` CLI의 require-by-string은 이를 못 따라가지만 Rojo/Studio 배포 경로는 무관함을 실측 확인, `selene`의 CWD 상대 config 탐색 함정, `.luaurc` alias 런타임 미지원 재확인, `pesde.lock` 커밋 권고(잠정). "확인 완료/아직 확인 안 된 것" 절이 다음에 뭘 검증해야 하는지의 소스 |
|
||||
| `typing-limits.md` | **[2026-08-13 열세 번째 세션 신설]** Luau 타입 시스템이 quad 설계에 대해 **못 해주는 것**을 한 군데 모은 확정 문서 — 여러 `base/` 문서에 캐비엇으로 흩어져 있던 걸 통합. 대전제는 "**Luau의 한계를 우회하려고 타입/API를 비틀지 않는다**"(비틀면 나중에 Luau가 고쳐줘도 자동 수혜를 못 받고 되돌리는 마이그레이션이 생김). 1번 항목이 가장 큼 — **재귀 제네릭이 다른 타입 인자로 자기를 반환하면(`Compute<U>(self: State<T>,...) -> State<U>`) 타입 안전성이 에러 없이 조용히 사라짐**(구 `question.md` 0-Y, 스파이크 다수로 확정 — 근거·개수는 `audit/type-recursion-issue/`). 대응은 두 개: (a) 타입 선언을 "데이터부/메소드부"로 쪼개 콜백 파라미터 추론을 살리고, (b) **파생 State를 만드는 자리마다 결과 타입을 명시 주석으로 바인딩**(그 한 줄만 검증 안 되고 다운스트림 전체는 정상 체크됨). Luau RFC `relax-recursive-type-restriction`이 `Promise<T>.andThen`으로 예시 든 바로 그 패턴이라 **지금 선언 그대로 두면 Luau 쪽 수정만으로 코드 변경 없이 풀림**(추적: `luau-lang/luau#2380`). **[2026-08-15 추가]** ③ 인라인 대신 이름 붙은 함수 + `typeof`로 선언하면 콜백 파라미터 주석은 여전히 필요하지만 LHS 명시 없이도 다운스트림이 안전해짐(①을 대체하지 않음, 보강). 그 외 Modifier `Overridden` 서브타입/Attribute 제네릭 키 narrowing/nilable default 오버로드도 여기 통합, `store.key` type function 한계는 **검증 완료로 승격**(§5), 7번에 **새 타입·API 설계 시 체크리스트**. 실측 근거는 `audit/type-recursion-issue/` + `audit/type-recursive-issue-with-typeof/` |
|
||||
| `lifecycle-pattern.md` | rbvm의 `Connected`+GC 관용구를 quad-v2가 채택하는 방식. **[2026-08-14 다섯 번째 세션, 시그니처 정정]** `bindLifetime(inst,value)`/`unbindLifetime(value)`/`canExecute(value)` — 뒤의 둘은 `inst`를 안 받음(`bindLifetime`이 바인딩 시점에 gcconn 참조를 `value` 쪽 `Relate`로 복사해두므로 `value` 하나로 생존을 물을 수 있고, 실제 호출부인 State 전파 루프엔 애초에 `inst`가 없음). `.Subscribed`는 전역 `:Subscribe()` 전용 필드로 분리(`bindLifetime`은 읽지도 쓰지도 않음), gcconn/gchold는 lazy가 아니라 **Instance 생성 시점**에 만들고 클로저가 `gchold`와 `inst`를 둘 다 캡처(userdata 포인터 동일성 = `inst`-키 `Relate` 전체의 전제). 옛 2-인자 모델은 `archive/canexecute-inst-arg-reversed.md`. **[2026-08-14 열한 번째 세션]** 별도 `canBound`가 다시 도입됨 — `bindLifetime`/`Observer:Subscribe()`의 이중 바인딩 가드는 `canBound`, State emit 전파 게이팅만 `canExecute`(판정 로직은 비공개 헬퍼 `isBoundAlive` 하나를 공유). **[2026-08-18 구현 전 QA 반영]** **두 predicate는 값이 같은 게 아니라 서로의 부정**(`canBound` 참 = "지금 묶어도 됨")이라 게이트가 전부 `if not canBound(v) then error(...)`로 정정됨 — 옛 서술대로 짰으면 정상 첫 바인드가 전부 에러났음. gcconn/gchold 저장도 `SetStrong`→**`SetWeak`** 정정 |
|
||||
| `store-plan.md` | **[2026-08-14 신설 — `bind-system-plan.md` 3단계 분할 + 구 store-semantics.md 흡수]** Store = **이름 붙은 Source 모음, 그 이상 아님** — Store 부작용 허용이 기본 디자인(국소적 vs 경계를 넘는 부작용), `defaults`는 선택적 초기값 템플릿(원본을 나중에 mutate해도 UB 아님)이고 **eager 생성과 lazy 생성이 둘 다 필요**(Luau 타입은 런타임에 강제 안 되므로), `table.clone` 기반 eager 생성 스케치, `store.key`(dot-access)가 1급 경로(**[2026-08-18] `store "key"` 문자열 커링은 기각** — 동적 키는 `store:GetDynamic<<T>>(name)`), 레코드 필드 타이핑은 Luau `type function`으로 해결 확인, `store.key = value` 폐기 → `store.key:Set(value)`(타입 대칭성+lazy 정직성), "Store가 Store를 저장 가능한가"는 **그런 경우를 안 만듦**으로 확정(`State<State<T>>`와는 다른 축) |
|
||||
|
|
|
|||
|
|
@ -187,13 +187,17 @@ quad는 이제 "스크립트"가 아니라 **라이브러리**다. DOMless Roblo
|
|||
pesde는 **네이티브 workspace**(Cargo 워크스페이스와 동형: 루트
|
||||
`workspace_members` + 멤버 간 `{ workspace = "scope/name", version = "^" }`
|
||||
의존)로 처음부터 1급 지원하므로, wally가 안고 있던 타입 정보 단절 문제
|
||||
자체도 이 전환으로 같이 해소될 것으로 기대(단, 이 세션은 pesde 바이너리가
|
||||
없는 샌드박스라 `pesde install`로 실제 링크 결과까지는 검증 못함 — 실제
|
||||
설치 검증은 사람이 로컬에서 `rokit install` 이후 확인할 것).
|
||||
자체도 이 전환으로 같이 해소됨 — **[2026-08-19 같은 날 후속 세션]**
|
||||
pesde/rojo 바이너리를 이 샌드박스에 직접 설치해 `pesde install`/`rojo
|
||||
build`까지 실제로 돌려 링크 결과를 확인 완료(`base/project-setup-plan.md`가
|
||||
소스, 워크스페이스 의존성이 symlink로 연결되고 Rojo는 이를 투명하게
|
||||
따라감).
|
||||
실제 구현: 루트 `pesde.toml`(`private = true`,
|
||||
`workspace_members = ["quad-base", "quad-roblox"]`) + `quad-base/pesde.toml`/
|
||||
`quad-roblox/pesde.toml`(각각 `[target] environment = "roblox"`,
|
||||
`quad-roblox`는 `quad-base`에 workspace 의존), 툴체인은 `rokit.toml`로 핀.
|
||||
`quad-roblox`는 `quad-base`에 workspace 의존), 툴체인은 `mise.toml`로 핀
|
||||
(`rokit.toml`에서 전환, 2026-08-19 사용자 결정 — 더 범용적인 도구라는
|
||||
판단, `base/project-setup-plan.md`의 "툴체인" 절 참고).
|
||||
pesde는 "패키지 안에 `default.project.json`을 두지 말 것"이 컨벤션(그
|
||||
파일은 소비자가 직접 만드는 sync 설정 몫) — 루트의 `default.project.json`은
|
||||
이 규칙의 예외가 아니라 애초에 그 규칙이 가리키는 대상이 아님(워크스페이스
|
||||
|
|
|
|||
|
|
@ -28,11 +28,13 @@ M3 이후 실제 구현이 아님 — `quad-base/src`는 아직 `Relate.luau`/
|
|||
```
|
||||
quad/
|
||||
├── pesde.toml # 워크스페이스 루트, private = true, workspace_members
|
||||
├── rokit.toml # pesde/rojo 버전 핀
|
||||
├── mise.toml # pesde/rojo/luau-lsp/selene 버전 핀
|
||||
├── quad-base/
|
||||
│ └── pesde.toml # name = "qwreey/quad_base"
|
||||
│ ├── pesde.toml # name = "qwreey/quad_base"
|
||||
│ └── selene.toml
|
||||
└── quad-roblox/
|
||||
└── pesde.toml # name = "qwreey/quad_roblox", quad_base에 workspace 의존
|
||||
├── pesde.toml # name = "qwreey/quad_roblox", quad_base에 workspace 의존
|
||||
└── selene.toml
|
||||
```
|
||||
|
||||
- **루트 `pesde.toml`**: `private = true`(게시 안 됨) + `workspace_members =
|
||||
|
|
@ -61,15 +63,33 @@ quad/
|
|||
갱신됨(`qwreey/quad`/`qwreey/quad_base`/`qwreey/quad_roblox` 셋 다
|
||||
스캔·링크).
|
||||
|
||||
## 툴체인 — `rokit.toml`
|
||||
## 툴체인 — `rokit.toml`에서 `mise.toml`로 전환 (2026-08-19)
|
||||
|
||||
`initreq/vide`(참고 레포)의 `rokit.toml` 선례를 따르되 wally 항목은
|
||||
뺐다. **[2026-08-19, 같은 날 후속 세션에 전부 완료]** `pesde`/`rojo`/
|
||||
`luau-lsp` **셋 다** `/code/.local/bin`에 직접 다운로드해 설치·검증
|
||||
완료 — 각각 `0.7.3`/`7.7.0`/`1.69.0`, `rokit.toml`의 핀과 정확히 일치.
|
||||
`rokit` 자체는 이 샌드박스에 없어 `rokit install`로 한 번에 검증한 건
|
||||
아니고 바이너리를 개별 다운로드해 버전을 대조한 것 — 실제 `rokit`
|
||||
워크플로 자체의 검증은 여전히 사람의 로컬 환경 몫.
|
||||
원래는 `initreq/vide`(참고 레포)의 `rokit.toml` 선례를 따랐음(같은 날
|
||||
`pesde`/`rojo`/`luau-lsp` 셋 다 `/code/.local/bin`에 직접 다운로드해
|
||||
설치·핀과 버전 일치까지 검증). **같은 날 후속 세션에 `mise.toml`로
|
||||
재전환** — 사용자 결정("요즘은 rokit 보단 mise로 까는듯 하네. 더
|
||||
범용적이라 이걸 택하는듯"), 근거는
|
||||
`Word30210/roblox-project-example`(`initreq/roblox-project-example`로
|
||||
클론해 확인)의 `mise.toml`. `rokit`은 이 샌드박스에 아예 없어 한 번도
|
||||
직접 검증 못 했던 반면, **`mise`는 이 샌드박스 자체가 이미 `luau` 설치에
|
||||
쓰고 있어서 `mise install`을 그 자리에서 실행해 진짜로 검증**함 —
|
||||
`pesde`/`rojo`/`luau-lsp`/`selene` 넷 다 GitHub artifact attestation +
|
||||
SLSA provenance 검증까지 거쳐 설치됨(이전 세션이 `curl`로 직접 받던
|
||||
방식보다 공급망 신뢰도가 높음), `mise exec -- <tool> --version`으로
|
||||
버전 일치까지 확인. `mise.toml`의 tool 키는 백엔드 접두사가 붙는다
|
||||
(`github:owner/repo` / `aqua:owner/repo`) — `rokit.toml`의 `owner/repo@ver`
|
||||
평문 표기와 형태가 다르니 그대로 베끼지 말 것.
|
||||
|
||||
**darklua는 검토 후 채택 안 함** — 참고 레포는 `.darklua.json`의
|
||||
`convert_require` 룰로 경로 기반 require를 빌드 시점에 Rojo sourcemap
|
||||
기준 `script.Parent`류로 변환하는데, **사용자 판단(2026-08-19)**: "Roblox
|
||||
안에서도 이미 string require가 적용되긴 하고, `@self`와 `@game`이
|
||||
먹는다. 같은 동작을 하지만 `./` 등으로 위치를 어떻게 두냐에 유의가
|
||||
필요할 뿐" — 즉 실제 Roblox 엔진도 이 세션이 확인한 것과 같은
|
||||
require-by-string 의미론(`@self` 등)을 그대로 지원하므로, darklua로 다른
|
||||
형태로 변환할 필요성 자체가 낮다는 판단. quad-base는 엔진 무관이어야
|
||||
하므로 애초에 Roblox 전용 변환의 적용 대상도 아님.
|
||||
|
||||
## require 구조 — `@self`가 필수인 이유
|
||||
|
||||
|
|
@ -183,6 +203,34 @@ require에서 여전히 안 먹는다** — `architecture.md`가 이미 이렇
|
|||
동작하는 것과 구분할 것). 그래서 alias는 편집기 자동완성/타입체크
|
||||
용도로만 남기고, 실제 require는 위 규칙대로 상대경로 + `@self`.
|
||||
|
||||
## `selene` 린터 — 패키지별 설정, CWD 상대 config 탐색 함정
|
||||
|
||||
**[2026-08-19 신설]** 사용자 결정으로 `selene`(참고 레포
|
||||
`initreq/roblox-project-example`의 `scripts/selene.toml` 그대로 채택)을
|
||||
도입 — `luau-analyze`(타입체크)와 겹치지 않는 별도 축(정의되지 않은
|
||||
변수, 사용 안 하는 변수, `assert` 메시지 누락 등 스타일/버그 패턴
|
||||
린트)이라 같이 씀. `quad-base/selene.toml`/`quad-roblox/selene.toml`
|
||||
각각 독립 배치(참고 레포도 패키지마다 독립 설정) — 아래 실측 이유 때문에
|
||||
루트 단일 설정은 안 씀.
|
||||
|
||||
**⚠️ `selene`의 `--config` 탐색은 파일 트리를 거슬러 올라가며 찾는 게
|
||||
아니라 CWD 기준 고정 경로(`./selene.toml`)다.** 루트에 `selene.toml`
|
||||
하나만 두고 `selene quad-base/`를 저장소 루트에서 실행하면, 그 자리엔
|
||||
`selene.toml`이 없어(패키지 폴더 안에 있으므로) **Luau 문법 자체를 못
|
||||
읽는 기본(Lua 5.1) std로 조용히 폴백** — `type Quad = {...}` 같은 평범한
|
||||
타입 선언까지 전부 "unexpected token" 파싱 에러로 쏟아짐(30여 건, 전부
|
||||
가짜). 처음엔 이게 "이 selene 빌드가 Luau 타입 문법을 아예 지원 못
|
||||
한다"는 뜻인 줄 알았으나, `std = "luau"`가 든 `selene.toml`을 CWD에
|
||||
두면 정확히 같은 파일이 0 에러로 통과함 — 즉 **문제는 selene의 Luau
|
||||
지원이 아니라 config 탐색 방식**이었다.
|
||||
|
||||
**규칙**: 항상 **패키지 디렉토리 안에서** 실행할 것 —
|
||||
`cd quad-base && selene .`(참고 레포의 Justfile도 정확히 이 패턴으로
|
||||
각 패키지를 순회함, `refresh`/`clean` 레시피). 저장소 루트에서
|
||||
`--config quad-base/selene.toml quad-base/`처럼 명시적으로 경로를
|
||||
지정해도 되지만, 그럴 거면 그냥 `cd`가 더 안전(설정 파일 지정을
|
||||
빠뜨리기 쉬움).
|
||||
|
||||
## `pesde.lock` — 커밋 권고 (미확정, 사용자 판단 필요)
|
||||
|
||||
**[2026-08-19 실측, 최초 서술 정정]** 처음엔 "워크스페이스 루트에 딱
|
||||
|
|
@ -217,7 +265,7 @@ lockfile들이 **게시되는 대상이 아니기** 때문 — 루트는 `privat
|
|||
- 워크스페이스 의존성이 symlink로 연결되고, 그게 `luau` CLI의
|
||||
require-by-string과 충돌한다는 것(직접 재현 + Luau RFC로 원인 확인)
|
||||
- **[2026-08-19 후속 세션]** Rojo(`/code/.local/bin`에 직접 설치,
|
||||
`7.7.0`, `rokit.toml` 핀과 일치)는 위 symlink 문제와 무관 — `rojo
|
||||
`7.7.0`, 툴체인 핀과 일치)는 위 symlink 문제와 무관 — `rojo
|
||||
sourcemap`/`rojo build` 둘 다 `roblox_packages`의 symlink를 실제
|
||||
파일까지 투명하게 따라감을 확인. 위 심볼릭 링크 함정은 Luau standalone
|
||||
CLI의 require-by-string 전용 문제로 범위가 좁혀짐
|
||||
|
|
@ -229,6 +277,12 @@ lockfile들이 **게시되는 대상이 아니기** 때문 — 루트는 `privat
|
|||
안 됨(`architecture.md`가 pesde 전환의 배경으로 들었던 문제 자체가
|
||||
실제로 해소됐다는 간접 증거). 산출물 `sourcemap.json`은 재생성되는
|
||||
빌드 산물이라 `.gitignore`에 추가
|
||||
- **[2026-08-19 셋째 후속 세션]** `mise.toml`이 `pesde`/`rojo`/`luau-lsp`/
|
||||
`selene` 넷 다 정확히 설치·버전 일치함을 `mise install` + `mise exec`로
|
||||
직접 확인(attestation/provenance 검증까지 포함) — `rokit`은 끝내
|
||||
한 번도 직접 검증 못 했던 것과 대비됨
|
||||
- `selene`의 `--config` 탐색이 파일 트리를 안 거슬러 올라가고 CWD
|
||||
기준 고정 경로라는 것(위 "`selene` 린터" 절)
|
||||
|
||||
**아직 확인 안 됨(다음에 도구/환경이 갖춰지면)**:
|
||||
- 루트 `pesde.toml`의 `[target]` 섹션이 실제로 의미가 있는지(지금은
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
# 2026-08-19, 다섯 번째 세션 — rokit→mise 전환, selene 린터 도입, darklua 검토 후 기각
|
||||
|
||||
**요약**: 사용자가 `Word30210/roblox-project-example`(참고용 GitHub 레포)의
|
||||
`mise.toml`을 보여주며 "요즘은 rokit보단 mise로 까는듯 하네" 언급.
|
||||
`initreq/roblox-project-example`로 클론해 구조 전체를 훑고 흡수할 요소를
|
||||
찾음 — mise 전환, selene 린터, darklua 세 후보 중 사용자가 앞의 둘만
|
||||
채택.
|
||||
|
||||
## 1. 참고 레포 훑기
|
||||
|
||||
`packages/`(독립 게시 패키지)+`places/`(멀티 플레이스 게임 프로젝트)+
|
||||
`scripts/`(빌드 도구) 구조, 각 서브패키지가 독립 `pesde.toml`/
|
||||
`selene.toml`/`stylua.toml`/`.luaurc`/`.vscode`를 가짐. `Justfile`로
|
||||
`refresh`/`clean`/`dev` 태스크 러너(각 패키지를 순회하며 `pesde
|
||||
install`+`darklua process` 반복). `.darklua.json`의 `convert_require`
|
||||
룰이 경로 기반 require를 Rojo sourcemap 기준 `script.Parent`류로 빌드
|
||||
시점에 변환. `places/main`의 `default.project.json`(로컬 dev, `src`
|
||||
직결)과 `build.project.json`(`dist`, darklua 처리 결과) 분리. `optional`
|
||||
path 문법(`{"$path": {"optional": "roblox_packages"}}`)으로 설치 전에도
|
||||
Rojo 에러 안 나게 함.
|
||||
|
||||
`packages/assets/src/init.luau`가 `require("@self/assets")`를 실제로
|
||||
씀 — 지난 세션에 발견한 `@self` 규칙의 세 번째 교차 확인(tbox, 이번
|
||||
세션 자체 실측에 이어).
|
||||
|
||||
## 2. 사용자 선택 — mise 전환 + selene 채택, darklua는 보류
|
||||
|
||||
멀티셀렉트로 네 후보(mise 전환/selene/darklua/Justfile) 제시,
|
||||
사용자 답: mise 전환(추천)과 selene은 채택. darklua에는 직접 반박 —
|
||||
*"roblox 안에서도 이미 string require가 적용되긴 하고, @self와 @game이
|
||||
먹는다. 같은 동작을 하지만, ./ 등으로 위치를 어떻게 두냐에 유의가
|
||||
필요할 뿐임. 따라서 darklua의 필요성은 잘 모르겠다"* — 즉 실제 Roblox
|
||||
엔진도 이 세션들이 확인해온 require-by-string 의미론을 그대로 지원하므로
|
||||
변환 계층이 불필요하다는 판단(Justfile은 언급 안 돼 도입 안 함).
|
||||
|
||||
## 3. mise 전환 — 실제 검증까지 완료
|
||||
|
||||
`/tmp`에서 먼저 `mise install`로 pesde/rojo를 테스트 — **GitHub artifact
|
||||
attestation + SLSA provenance 검증까지 거쳐 설치됨**(이전 세션이 `curl`로
|
||||
직접 받던 것보다 공급망 신뢰도가 높음). `rokit`은 이 샌드박스에 없어
|
||||
한 번도 못 써봤던 것과 대비되게, `mise`는 이 샌드박스 자체가 이미
|
||||
`luau` 설치에 쓰고 있어 실제 검증이 가능했음. `rokit.toml` 삭제,
|
||||
`mise.toml` 신설(`github:`/`aqua:` 백엔드 접두사 문법 — `rokit.toml`의
|
||||
평문 `owner/repo@ver`와 형태가 다름) — `pesde`/`rojo`/`luau-lsp`/
|
||||
`selene` 넷 다 `mise install`+`mise exec`로 버전 일치까지 재확인.
|
||||
|
||||
## 4. selene 도입 — CWD 상대 config 탐색 함정 발견
|
||||
|
||||
참고 레포의 `scripts/selene.toml`을 그대로 채택. 처음 루트에 단일
|
||||
`selene.toml`을 두고 `selene quad-base/`를 저장소 루트에서 돌렸더니
|
||||
`type Quad = {...}` 같은 평범한 타입 선언까지 전부 파싱 에러(30여 건) —
|
||||
"이 selene 빌드가 Luau 타입 문법 자체를 지원 안 하나?"로 오인했다가,
|
||||
최소 재현으로 `std = "luau"`가 CWD에 없으면 조용히 Lua 5.1 std로
|
||||
폴백한다는 걸 확인(`--config`가 파일 트리를 안 거슬러 올라감, CWD 기준
|
||||
고정 경로). 참고 레포처럼 **패키지별 독립 `selene.toml`**로 전환하고
|
||||
`cd quad-base && selene .`처럼 패키지 안에서 실행하는 걸로 확정.
|
||||
|
||||
부수로 `quad-base/test/smoke.mock.luau`의 `assert(cond)` 3건(메시지
|
||||
없음)이 selene의 `incorrect_standard_library_use`(deny)에 걸려 실제
|
||||
수정(메시지 추가) — 도입하자마자 실제 코드 품질 개선.
|
||||
|
||||
## 5. 산출물
|
||||
|
||||
- `mise.toml`(루트, `rokit.toml` 대체), `quad-base/selene.toml`,
|
||||
`quad-roblox/selene.toml` 신설.
|
||||
- `.claude/base/project-setup-plan.md` — "툴체인" 절 전면 갱신(mise 전환
|
||||
경위, darklua 기각 근거), "`selene` 린터" 절 신설.
|
||||
- `.claude/base/architecture.md`/`.claude/README.md`의 `rokit.toml`
|
||||
잔여 참조 정정.
|
||||
- `quad-base/test/smoke.mock.luau` — selene이 잡은 `assert` 메시지
|
||||
누락 3건 수정.
|
||||
- `initreq/roblox-project-example` 클론 보존(읽기 전용 참고 레포,
|
||||
`.gitignore`로 이미 제외되는 `initreq/` 하위라 커밋 대상 아님).
|
||||
13
mise.toml
Normal file
13
mise.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# mise-관리 툴체인 — `rokit.toml`에서 전환(2026-08-19 사용자 결정, "요즘은
|
||||
# rokit 보단 mise로 까는듯 하네. 더 범용적이라 이걸 택하는듯"). 이 판단은
|
||||
# `Word30210/roblox-project-example`(`initreq/roblox-project-example`,
|
||||
# 참고용으로 클론)의 `mise.toml`을 실제로 이 세션에서 `mise install`로
|
||||
# 검증하며 확인됨 — pesde/rojo를 GitHub artifact attestation + SLSA
|
||||
# provenance 검증까지 거쳐 설치함(이 세션이 직접 curl로 받았던 방식보다
|
||||
# 안전). 이 샌드박스 자체가 이미 mise로 `luau`를 관리 중이라 rokit보다
|
||||
# 자연스럽게 맞물림.
|
||||
[tools]
|
||||
"github:pesde-pkg/pesde" = "0.7.3+registry.0.2.3"
|
||||
"github:rojo-rbx/rojo" = "7.7.0"
|
||||
"github:JohnnyMorganz/luau-lsp" = "1.69.0"
|
||||
"aqua:Kampfkarren/selene" = "0.31.0"
|
||||
31
quad-base/selene.toml
Normal file
31
quad-base/selene.toml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
std = "luau"
|
||||
exclude = ["**/.pesde/*", "*_packages/*"]
|
||||
|
||||
[lints]
|
||||
almost_swapped = "deny"
|
||||
constant_table_comparison = "deny"
|
||||
deprecated = "warn"
|
||||
divide_by_zero = "warn"
|
||||
empty_if = "deny"
|
||||
empty_loop = "deny"
|
||||
high_cyclomatic_complexity = "warn"
|
||||
if_same_then_else = "deny"
|
||||
ifs_same_cond = "warn"
|
||||
incorrect_standard_library_use = "deny"
|
||||
manual_table_clone = "warn"
|
||||
mismatched_arg_count = "deny"
|
||||
mixed_table = "allow"
|
||||
multiple_statements = "deny"
|
||||
must_use = "warn"
|
||||
parenthese_conditions = "deny"
|
||||
suspicious_reverse_loop = "deny"
|
||||
type_check_inside_call = "deny"
|
||||
unbalanced_assignments = "warn"
|
||||
undefined_variable = "deny"
|
||||
unscoped_variables = "deny"
|
||||
unused_variable = "warn"
|
||||
|
||||
[config]
|
||||
empty_if = { comments_count = true }
|
||||
empty_loop = { comments_count = true }
|
||||
multiple_statements = { one_line_if = "break-return-only" }
|
||||
|
|
@ -29,9 +29,9 @@ do
|
|||
|
||||
local children = root:GetChildren()
|
||||
assert(#children == 2, "expected 2 children")
|
||||
assert(root:FindFirstChild("A") == child1)
|
||||
assert(root:FindFirstChild("B") == child2)
|
||||
assert(child1.Parent == root)
|
||||
assert(root:FindFirstChild("A") == child1, "FindFirstChild must locate child by Name")
|
||||
assert(root:FindFirstChild("B") == child2, "FindFirstChild must locate child by Name")
|
||||
assert(child1.Parent == root, "Parent must read back what was assigned")
|
||||
|
||||
child1.Parent = nil
|
||||
assert(#root:GetChildren() == 1, "removing Parent must detach from old parent's children")
|
||||
|
|
|
|||
31
quad-roblox/selene.toml
Normal file
31
quad-roblox/selene.toml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
std = "luau"
|
||||
exclude = ["**/.pesde/*", "*_packages/*"]
|
||||
|
||||
[lints]
|
||||
almost_swapped = "deny"
|
||||
constant_table_comparison = "deny"
|
||||
deprecated = "warn"
|
||||
divide_by_zero = "warn"
|
||||
empty_if = "deny"
|
||||
empty_loop = "deny"
|
||||
high_cyclomatic_complexity = "warn"
|
||||
if_same_then_else = "deny"
|
||||
ifs_same_cond = "warn"
|
||||
incorrect_standard_library_use = "deny"
|
||||
manual_table_clone = "warn"
|
||||
mismatched_arg_count = "deny"
|
||||
mixed_table = "allow"
|
||||
multiple_statements = "deny"
|
||||
must_use = "warn"
|
||||
parenthese_conditions = "deny"
|
||||
suspicious_reverse_loop = "deny"
|
||||
type_check_inside_call = "deny"
|
||||
unbalanced_assignments = "warn"
|
||||
undefined_variable = "deny"
|
||||
unscoped_variables = "deny"
|
||||
unused_variable = "warn"
|
||||
|
||||
[config]
|
||||
empty_if = { comments_count = true }
|
||||
empty_loop = { comments_count = true }
|
||||
multiple_statements = { one_line_if = "break-return-only" }
|
||||
11
rokit.toml
11
rokit.toml
|
|
@ -1,11 +0,0 @@
|
|||
# Rokit-관리 툴체인. `vide`(`.claude/initreq/vide/rokit.toml`) 선례를 따르되
|
||||
# wally 항목은 뺌(pesde로 전환, 2026-08-19 사용자 결정).
|
||||
#
|
||||
# [2026-08-19] pesde/rojo/luau-lsp 셋 다 이 핀 그대로 `/code/.local/bin`에
|
||||
# 직접 설치해 버전 일치까지 실측 확인 완료(`rokit` 자체는 이 샌드박스에
|
||||
# 없어 `rokit install`로 검증한 건 아님 — 바이너리를 개별 다운로드해
|
||||
# 대조). 상세는 `.claude/base/project-setup-plan.md`.
|
||||
[tools]
|
||||
pesde = "pesde-pkg/pesde@0.7.3+registry.0.2.3"
|
||||
rojo = "rojo-rbx/rojo@7.7.0"
|
||||
luau-lsp = "JohnnyMorganz/luau-lsp@1.69.0"
|
||||
Loading…
Reference in a new issue