Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,32 @@ jobs:

# Zero runtime deps and no lockfile, so there is nothing to install —
# run the suite directly (unit + e2e).
#
# The output is echoed back as annotations because raw CI logs are not
# reachable from the machines that maintain this repo: they are served
# from *.blob.core.windows.net, which the proxy answers with 403, so
# `gh run view --log-failed` fails. The annotations REST API is
# reachable, so a failure that only reproduces on CI stays diagnosable
# without asking someone to open a browser. Perf diagnostics are
# surfaced on every run, not just failures, because the useful signal
# for a timing flake is the numbers from the runs that passed.
- name: Run tests
run: npm test
run: |
set +e
npm test 2>&1 | tee test-output.txt
status="${PIPESTATUS[0]}"
set -e
annotate() {
local level="$1" line
while IFS= read -r line; do
line="${line//$'\r'/}"
if [ -n "$line" ]; then printf '::%s::%s\n' "$level" "$line"; fi
done
return 0
}
grep -E '^# spawn floor' test-output.txt | annotate notice || true
if [ "$status" -ne 0 ]; then
grep -E '^not ok |error: |exceeded the absolute ' test-output.txt \
| head -40 | annotate error || true
fi
exit "$status"
306 changes: 306 additions & 0 deletions docs/chad/boundary-perf-invariant/boundary-perf-invariant-artifact.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# boundary-perf-invariant — Context Card
<!-- working set only; UTF-8 <= 6 KiB, nonblank lines <= 100 -->

## Now
- Goal: boundary perf 테스트를 부하 불변 측정(비율 예산)으로 교체해 CI flake 제거, 회귀 탐지력은 강화.
- Current atomic step: 외부 read-only 리뷰 → PR 생성 → CI 확인.
- Stop / human-decision condition: 리뷰가 예산값(3x/5x) 또는 warmup 추가에 이의를 제기하면 사용자 판단.

## Constraints and settled decisions
- `max-parallel: 1` 는 **no-op** — hosted 러너는 matrix job마다 별도 VM (runner_name 상이). 되살리지 말 것.
- 예산은 차(ms)가 아니라 비(배수) — 감속계수가 소거되는 유일한 형태.
- hook 모양 baseline은 기각 — fork/exec 분산이 지배해 비율이 1 아래로 붕괴.
- 절대 상한 500/800ms 는 값 그대로 유지 (회귀 그물).
- min-of-N / median 재조합은 막다른 길 (지속 경합이라 전 샘플 오염).
- CI 로그는 프록시 403 — `gh run view --log-failed` 쓰지 말 것. 러너 메타는 `gh api .../jobs` 로 가능.

## JIT retrieval map
- Identifiers / symbols: `COLD_BUDGET`, `CHECKPOINT_BUDGET`, `baselineSource`, `runBoundaryCheck`
- Narrow globs: `tests/perf/boundary-checkpoint.test.mjs`, `src/commands/boundary.mjs`
- Read next: artifact.md 의 "예산 산정 근거" · "회귀 탐지력 입증" 표
- Verification command: `mise x node@20 -- node --test --test-concurrency=1 tests/perf/boundary-checkpoint.test.mjs`

## Failure capsules (max 3 unresolved)
- (none unresolved)

## Resume checklist
- 부하 재현은 스크래치패드 `with-load.sh` + `iterate.sh` (커밋 안 함). busy loop은 pidfile로 회수 —
`trap EXIT` 불발로 16개가 살아남아 "무부하" 측정을 오염시킨 전례 있음.
- 전/후 비교는 반드시 **동일 N · 동일 반복 횟수**로.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# boundary-perf-invariant — Handoff

(세션 종료 시 post-commit hook이 자동 갱신합니다)

## 2026-08-25T05:15:14.763Z — 9414faf fix(perf): boundary 예산을 동일 작업량 baseline 대비 비율로 교체
.../boundary-perf-invariant-artifact.md | 193 +++++++++++++++++++++
.../boundary-perf-invariant-context.md | 29 ++++
.../boundary-perf-invariant-handoff.md | 3 +
.../boundary-perf-invariant-meta.json | 7 +
.../boundary-perf-invariant-plan.md | 29 ++++
.../boundary-perf-invariant-spec.md | 103 +++++++++++
tests/perf/boundary-checkpoint.test.mjs | 140 +++++++++++----
7 files changed, 472 insertions(+), 32 deletions(-)

## 2026-08-25T05:15:34.514Z — c158b0c docs(handoff): post-commit hook 갱신 반영
.../boundary-perf-invariant/boundary-perf-invariant-handoff.md | 10 ++++++++++
docs/chad/chad-handoff.md | 6 +++---
2 files changed, 13 insertions(+), 3 deletions(-)

## 2026-08-25T05:19:56.055Z — c1f4656 docs(review): codex read-only 리뷰 결과·판별 기록, steady-state 명세 명확화
.../boundary-perf-invariant-artifact.md | 44 ++++++++++++++++++++++
.../boundary-perf-invariant-handoff.md | 5 +++
docs/chad/chad-handoff.md | 2 +-
tests/perf/boundary-checkpoint.test.mjs | 25 ++++++++----
4 files changed, 68 insertions(+), 8 deletions(-)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"user": "chad",
"task": "boundary-perf-invariant",
"created": "2026-08-25",
"status": "open",
"closedAt": null
}
29 changes: 29 additions & 0 deletions docs/chad/boundary-perf-invariant/boundary-perf-invariant-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# boundary-perf-invariant — Plan

## 목표
boundary perf 테스트를 **부하 불변** 측정으로 바꿔 CI flake를 없애되,
회귀 탐지력은 기존보다 **강화**한다.

## 단계
- [x] 브리프·테스트·CI 워크플로우 정독, 실패 assertion 특정 (`:110` 상대 예산)
- [x] 후보 (b) 검증 — `gh api .../jobs`로 러너 메타데이터 확인 → **hosted 러너, job별 독립 VM** → 기각
- [x] **수정 전** 로컬 재현: busy loop 16개(12코어) · 10회 → 4회 실패, 전부 `:110`
- [x] 동일 작업량 baseline 설계 — `boundary.mjs`의 I/O 패턴(stat→readFile→JSON.parse, 순차/동시) 미러링
- [x] delta vs ratio 비교 측정 → **ratio 채택**(부하 하 delta 3.6× 팽창 vs ratio 1.24× 팽창)
- [x] hook-shaped baseline 후보 측정 → **기각**(fork/exec 노이즈가 지배해 비율이 1 아래로 붕괴)
- [x] 예산 산정 — 부하 0/16/24/36 실측에서 cold 1.20–1.96 · checkpoint 2.19–3.65 → `3x` / `5x`
- [x] 모든 스폰 shape에 untimed warmup 추가 (절대 상한 자체의 flake 제거)
- [x] **수정 후** 동일 부하 반복 실행 — load 16 · 24 각 10회, load 36 8회 → **28/28 통과**
- [x] 회귀 탐지력 입증 — CPU burn 주입 mutation test로 신·구 가드 민감도 비교
- [x] 전체 스위트 통과 확인 (node 20 · 415 tests)
- [x] 전/후 `t.diagnostic` 수치를 artifact.md에 기록
- [x] 외부 read-only 리뷰 실행 및 artifact `## Reviews` 기록
- [x] PR 생성 및 CI 확인

## Ontology 변경 로그
- **equal-work baseline** 신설 — 기존 **spawn floor**를 assertion 분모 자리에서 밀어냈다.
spawn floor는 진단 전용으로 강등(삭제 아님 — 옛 CI 메시지와의 대조 가치).
- **ratio budget** 신설 — 예산의 단위가 `ms`에서 `배수`로 바뀌었다.

## 참고
- 부하 재현 스크립트는 스크래치패드에만 두고 저장소에 커밋하지 않는다 (일회성 조사 도구).
103 changes: 103 additions & 0 deletions docs/chad/boundary-perf-invariant/boundary-perf-invariant-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# boundary-perf-invariant — Spec

## 목적 / 요구사항

`tests/perf/boundary-checkpoint.test.mjs`의 `boundary performance` 테스트가 GitHub Actions에서
무작위로 실패한다. 문서 전용 diff에서도 발생하므로 변경 내용과 무관한 **측정 방식의 결함**이다.

깨지는 assertion은 중앙값 **상대 예산**(`coldMs - spawnFloorMs < 75`)이다. 분모가 bare
`node -e ''` 스폰이라 **스폰 비용 변동만** 상쇄한다. 부하에서는 CLI 본체 작업(20 × 10KiB 스키마
read+parse + 모듈 그래프 로드)도 같이 느려지는데, 그 **작업량 비례 지연을 분모가 흡수하지 못한다.**

요구사항:
1. 러너 전체 실행 시간 동안 **지속되는 부하**에서도 성립하는 측정으로 교체한다.
2. 절대 상한(`Math.max` 500ms / 800ms)은 회귀 그물로 **유지**한다.
3. 예산을 느슨하게 푸는 방식으로 green을 사지 않는다 — 진짜 느린 구현을 잡는 능력이
기존보다 **약해지면 안 된다.**

## 설계 / 접근

### 후보 평가

| 후보 | 판정 | 근거 |
|---|---|---|
| (a) 분모를 **동일 작업량 baseline**으로 교체 | **채택** | 아래 참조 |
| (b) `max-parallel: 1` 등 **경합 제거** | **기각 (no-op)** | 아래 참조 |
| (c) 부하 감지 시 skip | 불필요 | (a)가 성립하므로 커버리지를 지울 이유가 없다 |
| min-of-N / median 재조합 | 기각 | 지속 경합이라 3 샘플이 전부 오염 — min≈median |

**(b)를 기각한 근거 (측정으로 확인).** 원 메모는 "matrix 두 job 동시 실행에 따른 러너 자원
경합"으로 추정했으나 **사실이 아니다.** GitHub Actions REST API(`/actions/runs/<id>/jobs`)로
확인한 결과 두 job은 **서로 다른 hosted 러너 VM**에서 돈다:

```
run 32802292903: test (20) runner_name="GitHub Actions 1000000304" → failure
test (18) runner_name="GitHub Actions 1000000305" → success
run 32797110644: test (18) runner_name="GitHub Actions 1000000296"
test (20) runner_name="GitHub Actions 1000000297"
runner_group_name="GitHub Actions" (hosted), labels=["ubuntu-latest"]
```

하드웨어를 공유하지 않으므로 직렬화해도 얻는 것이 없다. 실패 job이 `test (18)` ↔ `test (20)`
사이를 **번갈아** 오간 것도 상호 경합보다 **VM별 독립 노이즈**에 부합한다. 진짜 원인은 hosted
러너(2 vCPU)가 올라탄 물리 호스트의 **noisy neighbour**이며, 이것은 **제거할 수 없고 측정으로
우회할 수밖에 없다.**

### 채택 설계 — 비율(ratio) 예산

동일 작업량 baseline: CLI 없이 **같은 21개 파일**(spec + 20개 계약)을 CLI와 **같은 방식**으로
(`stat` → `readFile utf8` → `JSON.parse`, 양쪽은 순차 · boundary는 동시) 읽고 파싱하는
`node` 스크립트. `src/`에서 아무것도 import 하지 않는다.

예산을 **차(subtraction)가 아니라 비(ratio)** 로 둔다. CPU starvation 하에서
wall time ≈ 작업량 × 감속계수이므로,

- 차: `(W_cold − W_base) × s` → **감속계수 s가 그대로 남는다**
- 비: `(W_cold × s) / (W_base × s)` = `W_cold / W_base` → **s가 소거된다**

즉 비율이 부하 불변량이다. 측정으로 확인한 값(§Ambiguity 근거 참조):
부하 0 → 16 → 24 → 36에서 cold 비율은 1.20–1.96 범위에 머물렀고,
**부하를 3배로 올려도 더 나빠지지 않았다** — 불변성이 실제로 성립함을 뜻한다.

### 함께 고친 것 — CLI/hook warmup

기존 테스트는 bare 스폰만 untimed warmup 했다. CLI는 이 저장소의 ~20개 모듈 그래프를
컴파일해야 하므로 **첫 호출의 일회성 비용이 훨씬 크다**(부하 중 첫 cold 샘플 453–541ms,
정상 상태 60–90ms). 이 때문에 **절대 상한 500ms 자체가 flake 원인**이었다(541.3ms 관측).
bare에 이미 적용된 것과 **동일한 논리**를 모든 스폰 shape에 대칭 적용한다. 예산을 푼 것이
아니라 측정을 고친 것이다.

## Ontology

- **spawn floor**: bare `node -e ''` 실행 시간. 기존 설계의 분모. 이제는 **진단 출력 전용**이며
assertion에 쓰이지 않는다 — 옛 CI 실패 메시지와 수치를 대조할 수 있도록 남긴다.
- **equal-work baseline**: CLI가 읽는 것과 **정확히 같은 파일을 같은 방식으로** 읽고 파싱하되
CLI 자신의 비용(모듈 그래프 · 인자 해석 · spec 정규식 · 스키마 대조)은 지불하지 않는 기준선.
예산이 bound 하는 대상은 바로 이 **차이**다.
- **ratio budget**: `coldMs / baselineMs`. 부하 불변량 — 감속계수가 분자·분모에서 소거된다.
- **absolute ceiling**: `Math.max(samples) < 500/800ms`. 비율이 어떻게 되든 **지속적으로 느린
구현**을 잡는 회귀 그물. 이번 변경에서 **값을 건드리지 않았다.**

## Ambiguity 자가진단

- [x] **Goal 명확도** (40%) — "지속 부하에서도 성립하는 측정으로 교체하되 회귀 탐지력을 낮추지 않는다."
- [x] **Constraint 명확도** (30%) — 절대 상한 유지 · 예산 완화 금지 · CI 로그 접근 불가(프록시 403).
- [x] **Success 기준** (30%) — 수정 전 재현된 실패가 **동일 부하**에서 사라지고,
주입한 회귀를 **기존보다 더 민감하게** 잡는다(아래 수치로 입증).
- [x] **Context 명확도** — `tests/perf/boundary-checkpoint.test.mjs` 단일 파일. src 변경 없음.
- [x] **Ambiguity ≤ 0.2**

근거: 위 Ontology의 네 개념(spawn floor / equal-work baseline / ratio budget / absolute ceiling)이
구분되면서 "무엇을 어디에 대고 재는가"가 확정됐고, (b) 기각이 추정이 아니라 러너 메타데이터
측정으로 결론났다.

## Done evidence

```json
{ "version": 1, "review": "required", "tests": "required" }
```

## 참고
- 측정치·근거 원본(종결 task, 참조 전용): `docs/chad/release-0181-recovery/release-0181-recovery-artifact.md`
- CI 로그는 프록시가 `*.blob.core.windows.net`을 403으로 막아 이 머신에서 받을 수 없다.
러너 메타데이터는 JSON API(`gh api .../jobs`)로 받을 수 있으며 이번 (b) 기각 근거가 됐다.
6 changes: 3 additions & 3 deletions docs/chad/chad-handoff.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Session Handoff

## Active Task
sim-spec-coverage
boundary-perf-invariant

## Last Commit (2026-08-25)
3a72534 chore(task): 대기 프로토콜·신호 조건 기록
c1f4656 docs(review): codex read-only 리뷰 결과·판별 기록, steady-state 명세 명확화

## Full Context
→ docs/chad/sim-spec-coverage/sim-spec-coverage-handoff.md
→ docs/chad/boundary-perf-invariant/boundary-perf-invariant-handoff.md
Loading
Loading