Skip to content

feat(v0.11): ADR 0011 freeze + Track A — sentinel install one-shot - #47

Merged
Raunplaymore merged 1 commit into
mainfrom
feat/v0.11-track-a-install-command
May 5, 2026
Merged

feat(v0.11): ADR 0011 freeze + Track A — sentinel install one-shot#47
Raunplaymore merged 1 commit into
mainfrom
feat/v0.11-track-a-install-command

Conversation

@Raunplaymore

Copy link
Copy Markdown
Owner

Summary

v0.11 사이클 첫 PR. 사용자 피드백 — "이번 업그레이드 경험은 매우 간단했어. 그런데 첫 설치 경험은 너무 복잡하고 어려웠어." — 닫기.

이전:

pipx install sentinel-mac
sentinel --init-config              # 별개 명령
# plist 수동 작성 (XML 직접)
launchctl load ~/Library/LaunchAgents/com.sentinel.agent.plist
sentinel doctor                     # 검증

v0.11 이후:

pipx install sentinel-mac
sentinel install

ADR 0011 freeze (Status: Proposed)

Decision freeze 내용
D1 sentinel install [--force|--no-launchagent|--yes|--json]. exit 0/1/2/3
D2 7단계: detect → config → data dir → plist → launchctl load → verify → banner. 단계별 rollback
D3 PIPX/PIP_VENV 지원. EDITABLE/HOMEBREW/SYSTEM_UNSAFE는 exit 3
D4 artifact별 부분 보강. 모두 healthy면 exit 2. --force로 전체 재생성
D5 기존 dev install (.venv/bin/sentinel 패턴) 충돌 시 abort + 안내. --force로 백업 후 덮어쓰기
D6 (Track B 후속) sentinel uninstall 대칭
D7 sudo 불필요. FDA / 알림 권한은 macOS 자동 prompt
D8 성공 banner: config / data dir / daemon PID / Next Steps
D9 install.sh는 dev 전용 유지. README Quick Start 재정렬 (Track C)
D10 메뉴바 wizard는 v0.11.1 후속 분리

ADR amendment (planner 초안 → 사용 시점에 수정): D2 step 7의 doctor verify를 direct call → subprocess 호출로 변경. ADR 0010 §D3 verify_running_version 패턴 일관 + 두 호출 지점 동기화 부담 제거.

Track A 구현

신규:

  • sentinel_mac/installer/__init__.py
  • sentinel_mac/installer/plist.py (~150 LOC) — pure plist XML 생성, 0o644 write, 기존 plist binary path parsing (D5 conflict detection)
  • sentinel_mac/installer/config_init.py (~85 LOC) — config.example.yaml 템플릿에서 idempotent config 생성 (importlib.resources)
  • sentinel_mac/installer/verify.py (~101 LOC) — launchctl list → PID 추출 → sentinel --version subprocess 매칭 → sentinel doctor subprocess
  • sentinel_mac/commands/install.py (~341 LOC) — D2 7단계 오케스트레이션 + rollback + JSON envelope (kind=install)
  • sentinel_mac/config.example.yaml — 패키지 동봉 (wheel에 포함되도록 pyproject.toml [tool.setuptools.package-data] 명시)
  • tests/test_cmd_install.py (18 tests) — happy path / idempotent / unsupported method / D5 conflict / non-TTY / --json / --force rollback
  • tests/test_installer_plist.py (15 tests) — XML validity / field 정확도 / 권한 / 기존 plist parsing
  • tests/test_installer_config_init.py (10 tests) — 템플릿 발견 / 생성 / idempotency / force overwrite

수정:

  • sentinel_mac/core.py — argparse install subcommand dispatch (5줄)
  • pyproject.toml[tool.setuptools.package-data] 추가 (config.example.yaml 동봉)
  • docs/decisions/0011-first-install-flow.md — ADR + D2 step 7 subprocess 명시
  • CHANGELOG.md [Unreleased]에 freeze + Track A 항목

총 +2254 LOC.

Verification

  • mypy clean (30 source files — +5 신규 모듈)
  • ruff clean (sentinel_mac + tests)
  • pytest 950 passed (907 + 43 신규)

Test 시나리오 (43개)

  • happy path (PIPX) — exit 0, banner 출력
  • 이미 healthy install — exit 2
  • artifact 부분 누락 — 빠진 것만 보강
  • D5 dev .venv plist 충돌 — abort + migration 안내
  • D5 + --force — 백업 후 덮어쓰기
  • EDITABLE / SYSTEM_UNSAFE / HOMEBREW — exit 3 + guidance
  • non-TTY + no --yes — auto-cancel + WARNING (ADR 0009)
  • --no-launchagent — plist/load skip
  • --json — ADR 0004 §D2 envelope kind="install" / "install_error"
  • launchctl load 실패 — rollback (생성한 artifact 삭제) + exit 1
  • verify 실패 (--version 매치 안 됨) — 명확한 에러

Next steps (이 PR 머지 후)

  • Track Bsentinel uninstall 대칭 명령 (별도 PR, 작은 작업)
  • Track C — README Quick Start 재정렬 + install.sh 헤더 갱신 + ADR Status: Proposed → Accepted
  • v0.11.0 release ceremony

Test plan

  • mypy / ruff / pytest local
  • ADR amendment applied (D2 step 7 subprocess)
  • config.example.yaml 패키지 동봉 명시
  • CI green 확인 후 머지

🤖 Generated with Claude Code

Complete implementation of first-install flow following ADR 0011 §D2 sequence:
1. Install method detection (reuses ADR 0010 D1)
2. Config initialization from template (idempotent)
3. Data directory creation
4. LaunchAgent plist generation + write
5. launchctl load
6. Daemon liveness check (2s sleep + launchctl list)
7. Post-install banner (per ADR 0011 §D8)

Implemented modules:
- sentinel_mac/installer/plist.py — plist generation, conflict detection (D5)
- sentinel_mac/installer/config_init.py — config template handling
- sentinel_mac/installer/verify.py — daemon liveness + banner builder
- sentinel_mac/commands/install.py — full 7-step orchestrator

Features:
- D4 Idempotency: handles partial installs, --force override
- D5 Conflict detection: detects dev .venv vs PIPX, guides migration
- Exit codes: 0 (success), 1 (error), 2 (already installed), 3 (unsupported method)
- Flags: --force, --no-launchagent, --yes, --json
- Non-TTY behavior: auto-cancel with WARNING (ADR 0009 pattern)
- JSON output: ADR 0004 §D2 envelope format
- Rollback on failure: cleans up newly created artifacts

Tests: 43 new tests covering happy path, idempotency, conflicts, unsupported methods,
non-interactive mode, JSON output, dispatch entry point.

Code quality:
- mypy: clean
- ruff: clean (fixed all lint issues, proper exception chaining)
- pytest: 950 tests pass (907 existing + 43 new)

ADR amendment: D2 step 7 updated to document subprocess pattern for doctor
(following ADR 0010 §D3 consistency).

Package data: config.example.yaml now included in wheel via pyproject.toml
setup.py-style package-data configuration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Raunplaymore
Raunplaymore merged commit d2867ee into main May 5, 2026
5 checks passed
@Raunplaymore Raunplaymore mentioned this pull request May 5, 2026
9 tasks
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.

1 participant