diff options
| author | eunhhu <[email protected]> | 2026-09-29 18:15:16 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-29 18:15:16 +0100 |
| commit | c72284953bb6938ff480ae9be11d5d0c3c4154f6 (patch) | |
| tree | 4cca9983191de339007611af43137d5c0d12a08d /docs/research/103-review-004-defects.md | |
| parent | b09bda62059e11ee43ae6d1fd62bf31e2e4fbde6 (diff) | |
| download | pure-c72284953bb6938ff480ae9be11d5d0c3c4154f6.tar.gz pure-c72284953bb6938ff480ae9be11d5d0c3c4154f6.zip | |
Say how review 004's seven defects went (103)
Three broke what data means (a walk's range missed the indices an insert
moves; an uncertain save of numbers alone let the next save through; an
output whose fields swapped names kept its waiting sends), four were
errors (a stateless timer never ticked, Vega's terminal lost a key cut
across reads, an input named edit forced documents, timers waited on the
wall clock). Each is fixed with a check that fails on the code before
and passes now, in Pure's and Vega's make check. The review's other
advice (a whole app's memory budget, one real app grown, comparisons with
their conditions set first) is what comes next.
Diffstat (limited to 'docs/research/103-review-004-defects.md')
| -rw-r--r-- | docs/research/103-review-004-defects.md | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/docs/research/103-review-004-defects.md b/docs/research/103-review-004-defects.md new file mode 100644 index 0000000..3273ab3 --- /dev/null +++ b/docs/research/103-review-004-defects.md @@ -0,0 +1,61 @@ +# 103 — 외부 리뷰 004의 결함 일곱: 의미를 지키는 경계 + +2026-09-29. [외부 리뷰 004](../outside-feedback/feedback-004.md)가 찾은 결함을 고친다. 데이터의 의미를 깨는 P1이 셋이고, 기능 +오류인 P2가 넷이다(리뷰가 새로 찾은 둘, 앞 리뷰에서 남은 둘). 리뷰는 다음 확장보다 이 경계를 먼저 고치라고 권했다. + +착수 기준: + +- **바꿀 결정.** 없다. 계약을 고치는 것이다. 최적화 전후에 결과가 같고, 실패 뒤 복구 상태가 같고, 스키마가 바뀐 뒤에도 메시지의 + 뜻이 같아야 한다. +- **최소 확인.** 리뷰의 재현 사례를 회귀 검사로 넣는다. 그 검사가 옛 코드에서 실패하고 새 코드에서 통과하는 것을 본다. +- **중단 기준.** 고친 것이 기존 검사(Pure `make check`, Vega `make check`)를 하나라도 깨면 되돌린다. + +## 쉬운 말로 + +- 알아낸 것: + - 일곱 모두 리뷰가 말한 그대로 재현됐고, 모두 고쳤다. + - 일곱 모두 검사가 있다. 옛 코드에서 실패하고 새 코드에서 통과한다. + - 두 저장소의 `make check`가 통과한다. +- 공통점: 셋은 "암묵적인 것"을 세지 않은 데서 나왔다. + - F1: 삽입이 옮기는 index + - F3: 필드의 이름 + - F4: outbox도 상태라는 것 +- 아직 하지 않은 것: 리뷰의 권고 가운데 앱 전체 메모리 예산, 실제 앱 하나를 키우는 일, 조건을 맞춘 성능 비교의 확대는 다음 + 일이다(아래 "다음"). + +## 한 것 + +| | 결함 | 원인 | 고침 | 검사(옛 코드 → 새 코드) | +|---|---|---|---|---| +| F1 · P1 | 범위 최적화가 반복 결과를 바꾼다 | 반복 몸체의 쓰기에 삽입·삭제가 옮기는 index(와 텍스트 편집이 옮기는 커서)를 세지 않았다 | 그 상태도 쓴 것으로 센다. index를 옮기는 경계는 몸체가 어느 리스트도 바꾸지 않을 때만 범위를 쓴다 | `build/module-probe`가 범위를 쓴 실행과 안 쓴 실행을 비교한다. 리뷰의 앱: done 1 대 5로 다름 → 같음(10, 10) | +| F2 · P1 | 트리만 바꾼 저장의 불확실성이 앱을 멈추지 않는다 | `uncertain` 표시가 리스트 로그가 있을 때만 섰다 | 트리 커밋이 불확실하면 늘 세운다 | test-module `uncertain_numbers`: 리스트만 바꾸는 다음 사건이 저장됨 → 거절됨 | +| F3 · P1 | 출력 필드의 순서를 바꾸면 대기 메시지의 뜻이 바뀐다 | 교체와 재시작이 필드 개수와 타입만 비교했고, 저장된 links(PLK3)에 이름이 없었다 | 이름도 비교하고, links를 PLK4로 올려 필드 이름을 둔다. PLK3은 전처럼 타입만 본다 | test-module `output_meaning`: 교체와 재시작 모두 PURE_OK → CONFLICT | +| F4 · P2 | 상태 없이 출력만 보내는 타이머가 돌지 않는다 | 타이머가 상태가 있는 앱에서만 돌았다 | 상태나 출력이 있으면 돈다 | check.py `server_timers`: 틱 0 → 22 | +| F5 · P2 | Vega TUI가 나뉘어 온 방향키를 잃는다 | read 한 번 안에서 끝난 escape 시퀀스만 찾았다 | 끝나지 않은 시퀀스, 마우스 보고, UTF-8 문자는 다음 read까지 둔다. ESC 하나는 100 ms, 시작된 키는 1초까지 기다린다 | Vega check.py `interactive(cut=True)`: 초점이 안 움직여 엉뚱한 줄이 완료됨 → 옳게 움직임 | +| 앞 리뷰 P2 | 입력 이름 edit/show가 문서 모드를 강제한다 | 입력 이름으로 문서 앱을 판정했다 | 모듈이 키로 여는 collection을 선언했을 때만 문서 앱이다 | check.py `server_plain_edit`: 시작 거부 → 시작, POST 적용 | +| 앞 리뷰 P2 | 주기 타이머의 마감을 wall clock으로 셈한다 | Pure `run_timers`와 Vega `vega_timers_run`이 마감과 앱의 now를 같은 wall clock으로 셌다 | 마감은 monotonic clock으로 세고, 앱의 now만 wall clock으로 둔다 | `build/clock-back.so`(clock_gettime의 LD_PRELOAD)로 wall clock을 0.2초에 한 시간 되돌린다. Pure 틱 9에서 멈춤 → 29–39, Vega 9 → 40 | + +- **F1의 범위.** 범위를 쓰는 `where`에 들어올 수 있는 연산은 `has_lanes`가 정한다. 그래서 경계가 읽을 수 있는 상태는 수, index, + 지역 변수, 리스트 읽기, INDEX_MOVE(피연산자 index의 리스트 길이)뿐이다. 커서는 그 안에 들어오지 못하지만, 같은 규칙으로 함께 + 센다. 차등 탐침은 범위가 여전히 붙는 반복도 함께 돌려(`ranged` 1), 최적화가 필요한 곳에서 꺼지지 않았음을 본다. +- **F3의 옛 저장.** PLK3 저장에는 필드 이름이 없어 이름까지는 비교하지 못한다. 새 코드가 한 번 저장하면 PLK4가 된다. 저장을 + 이어받은 뒤 필드를 재배치한 모듈로 바꾸는 경우만 여전히 타입까지만 본다. +- **시계 검사의 방법.** 이 기기에서 시스템 시계를 바꿀 권한은 없고, 바꿔서도 안 된다. 그래서 `CLOCK_REALTIME`만 한 시간 + 뒤로 돌리는 LD_PRELOAD 라이브러리를 썼다. Vega의 검사도 Pure가 만든 이 라이브러리를 쓴다(`make check`가 넘긴다). + +## 리뷰의 다른 지적 + +- **micro-runtime의 전체 자원 한도.** 맞다. `--budget`은 입력과 반환의 payload admission만 묶는다. 앱의 리스트, outbox, 스냅숏, + 체크포인트까지 합친 한도와 넘칠 때의 정책(거절, 대기, 저장으로 넘김)은 아직 없다. 다음 일의 첫째다. +- **실행 모델.** 맞다. aup 앱은 C로 쓴 실행기가 모듈 명령을 해석해 돈다. 성능과 코드 크기는 이 비용을 포함해 말한다. +- **이벤트의 실행량.** 모듈이 유한해도 EACH와 fold의 일은 리스트 크기를 따른다. 앱별 시간 한도는 아직 없다. +- **전송 비교.** 이 리뷰 뒤 M6를 ngtcp2와도 쟀다([102](102-adoption-and-spec.md)). 어느 네트워크에서나 QUIC보다 낫다고 + 말하지 않는다. 102도 조건과 차이의 원인을 함께 적는다. + +## 다음 + +리뷰의 순서를 따른다. + +1. 앱 전체 메모리 예산: 느린 수신자와 오래 열린 스냅숏이 있을 때 앱 전체 사용량을 재고, 넘칠 때의 정책을 정한다. +2. 보드·메신저 계열의 실제 앱 하나를 키운다. 필드 추가와 재배치, 연결 중단, 재시작과 재동기화를 반복하며 작성 경험을 기록한다. +3. 조건(저장 완료 기준, 지연, 메모리)을 먼저 정한 성능 비교를 넓힌다. |
