Repository navigation
research: investigate external MCP event triggers for Dots recovery #43
Description
2026-10-23 현재 진행
검토용 Draft PR: #46. 관측 전달을 전용 HTTPS 인증으로 전환했고, 전달·구독 상태 감시와 claim 전 중단 사유 기록을 연구 서버에 적용했습니다. 플러그인 도구 목록과 작업 지침도 갱신했습니다. 이전 성공은 재인증·지침 수정·재개 요청이 개입한 복구로 유지하며, 다음 사람 개입 없는 자연 장애를 관찰합니다. 실제 장애 알림 전달과 장기 갱신은 추가 실측 대상입니다.
목적
외부 감시 시스템에서 Dots에 연결 실패 이벤트를 전달하고, Dots가 자신의 클라우드 컴퓨터에서 복구 명령을 실행할 수 있는지 조사합니다.
#20의 독립적인 실행 경로 연구를 구체화한 하위 조사입니다. 기존 watchdog의 프로세스 판정·같은 부팅 내 복구 실험은 #20에서 유지하고, 이 이슈는 Dots 밖에서 시작하는 이벤트 전달과 플랫폼 측 실행 가능성에 집중합니다. 자동 복구 구현이나 릴리스 포함을 약속하지 않습니다.
배경과 확인된 근거
- 기존 watchdog은 같은 부팅에서 식별 가능한 개별 프로세스 종료 복구가 검증됐지만, 새 실행 환경에서 watchdog 자체를 시작하는 경로는 미해결입니다. #20의 실측과 연결합니다.
- 공식 MCP Events 문서는 Dots 지원을 명시합니다. 사용자가 플러그인을 연결하고 감시 대상·대응 방법을 지정하면 ChatGPT가 이벤트를 구독하며, 외부 MCP 서버가 발급된 callback URL에 서명된 webhook을 전달합니다.
- 이는 임의의 개인 Dots 대화에 메시지를 보내는 공개 API나 VM 직접 shell API와 다릅니다.
- webhook의 2xx는 수신 확인이며, 명령 실행이나 외부 연결 복구 성공을 의미하지 않습니다.
- 공식 문서만으로 새 VM에서의 명령 실행, 지연, 승인 대기, 컴퓨터 준비 실패 및 GUI/agent/SSH 실행 환경의 동일성은 보장되지 않습니다.
조사할 구성
Mac mini의 외부 연결 감시 → Dots 밖의 지속 실행 MCP 이벤트 서버 → 사전 구독된 연결 실패 이벤트 → Dots의 클라우드 컴퓨터에서 승인된 복구 절차 → 외부의 새 SSH·Tailscale ping으로 결과 확인.
이벤트 서버는 Dots의 Tailscale 연결 및 VM 수명에 종속되지 않아야 합니다. 이벤트 payload에는 관측 데이터를 담고, 실행할 작업과 권한은 사용자가 사전에 지정합니다. 실제 호스트 정보·계정·구독 callback·비밀은 공개 이슈에 기록하지 않습니다.
단계별 조사 및 검증
- 계정에서 custom MCP plugin과 Dots 이벤트 구독이 사용 가능한지 확인하고, 필요한 인증·권한·운영 위치를 정리합니다.
- 인증된 최소 이벤트 서버의 설계를 작성합니다. events/list·subscribe·unsubscribe, callback 검증, 서명, 구독 지속 저장·갱신 및 제한된 재시도를 포함합니다.
- 먼저 무해한 이벤트 한 건으로 Dots 수신·응답을 확인합니다. 전달 수신과 실제 Dots 응답을 별도 기록합니다.
- Dots가 자기 클라우드 컴퓨터에서 읽기 전용 명령을 수행할 수 있는지 확인합니다. UID/PATH, /workspace 파일, runtime socket 가시성 및 다른 실행 환경으로의 위임 여부를 구분합니다.
- 독립 복구 경로와 승인 범위를 확보한 뒤 start.sh 실행 시험을 수행합니다. 기존 state가 보존되면 같은 노드 재연결을 확인하고, state/SSH identity 소실 시 안전한 중단 조건을 유지합니다.
- 이벤트 서버를 Dots 밖에 둔 상태에서 Tailscale 단절 시 전달 가능성을 확인합니다. 모든 프로세스가 살아 있는 네트워크 장애와 개별 프로세스 종료도 구분합니다.
- 실제 새 부팅 또는 환경 전환을 관찰하면 이벤트 → 클라우드 실행 → 외부 접속 복구를 단계별 확인합니다. 새 부팅이 관찰되지 않았다면 미검증으로 남깁니다.
- 중복 알림·동시 실행·연속 장애·구독 만료·서버 재시작·승인 대기·컴퓨터 미준비를 검증합니다. cooldown, 중복 억제, 실행 횟수 제한 및 결과 불명 시 재실행 방지 정책을 정리합니다.
- Slack/Teams 및 예약 작업을 보조 경로로 비교합니다. 봇 알림의 Dots 트리거 여부와 새 환경에서 실행 가능성은 실측 전까지 지원 완료로 취급하지 않습니다.
완료 조건
- 이벤트 발생·전달 수신·Dots 응답·명령 실행·외부 복구 확인을 서로 다른 단계로 기록합니다.
- 각 단계의 조건, 지연, 실패·중단 조건, 재현 절차와 증거를 남깁니다.
- 현재 환경에서의 성공과 새 부팅 이후의 성공을 구분합니다. 공개 결과에는 비밀이나 원시 개인 로그를 포함하지 않습니다.
- 가능·조건부 가능·불가·근거 부족 중 판정과 근거를 정리하고 #20에 요약을 연결합니다.
- 구현이 타당하면 별도 변경 범위와 운영 부담을 제안합니다. 연구 이슈를 제품의 자동 복구 지원 보장으로 해석하지 않습니다.
범위 제한
이슈 등록은 외부 서비스 설치, OAuth·계정 연결, 메시지 전송, 자동화 등록 또는 실환경 장애 주입 자체의 승인이 아닙니다. 기존 연결·상태·개인키를 삭제하거나 플랫폼 제한을 우회하지 않습니다. 실환경 변경은 검토 가능한 설계와 시험 범위를 마련한 뒤 수행합니다.
공식 자료 및 관련 이슈
- MCP Events
- MCP authentication
- Message your dot
- Connect computers and apps
- Tasks and memory
- research: validate Dots lifecycle, recovery, and proxy compatibility #20: lifecycle・독립 실행 경로・복구 범위 연구
- feat: add opt-in automatic updates with recovery safeguards #31: opt-in 자동 업데이트. 본 이슈는 업데이트 실행 경로를 제공하거나 자동 업데이트를 승인하지 않습니다.
Activity
abruption commentedon Oct 22, 2026
2026-10-22 연구 시작 및 1차 검증
격리 워크트리에서 synthetic MCP Events 프로토타입을 준비했습니다. 현재는 가짜 이벤트 전달 연구용이며 원격 shell 도구나 실제 감시 알림의 자동 전달 기능은 없습니다.
확인한 결과
배포 및 인증 설계
기존 HTTPS reverse proxy와 browser SSO를 사용하되, SSO는 신규 OAuth consent 경로에만 적용합니다. MCP endpoint는 OAuth bearer token, token endpoint는 정확한 client/redirect/resource 및 S256 PKCE를 검증합니다. 원문 토큰 대신 hash를 보관하고, webhook secrets/구독 데이터는 저장소 밖의 private runtime에 둡니다.
신규 도메인에는 별도 consent 접근 규칙이 필요합니다. 적용 helper는 기존 설정 보존·private backup·후보 검증·실패 시 원복을 준비했습니다. SSH 계정은 sudo 그룹에 속하지만 현재 비대화형 sudo는 비밀번호를 요구하므로, 운영자의 로컬 sudo 인증을 기다립니다. 기존 기본 정책을 변경하지 않습니다.
아직 확인하지 않은 항목
다음 단계는 공개 경로·OAuth 연결을 확인한 후
dots.recovery_probe한 건의 수신을 시험하는 것입니다. #20의 자동 복구 한계 판정은 아직 변경하지 않습니다.abruption commentedon Oct 22, 2026
2026-10-22 실측: 외부 이벤트 수신과 지연된 읽기 전용 점검 확인
OAuth 연결과 실제 MCP Events 구독·callback 검증을 완료했습니다.
확인된 결과
mcp43-20261022-readonly-02재시험 등록부터 결과 보고까지 추가 Dots 메시지, 이벤트 재전송 또는 Run now를 사용하지 않았습니다. 결과는 사용자 전달문만으로 판단하지 않고 ego-browser에서 Dots 대화를 직접 열어 대조했습니다.
지연과 증거 범위
이벤트 시각에서 Dots가 보고한 점검 시각까지 약 **1,174.27초(19분 34초)**입니다. 결과는 UID 1000,
/workspace/.dots-tailscale/start.sh존재·읽기 가능,/tmp/dots-tailscale-1000/tailscaled.sock존재입니다. 점검 시각과 실행 환경은 Dots의 결과 보고이며 별도로 수집한 원시 shell trace는 아닙니다.사용자는 Gmail 기반 알림에서 약 10분 또는 49분 지연을 관찰했다고 알려주었습니다. 이에 짧은 관찰을 실패로 단정하지 않고 관찰 구간을 늘렸습니다. 공식 문서도 HTTP 2xx를 접수 확인으로 구분하고 비동기 처리·batching 가능성을 설명하지만, 고정 10분/20분 주기나 최대 지연은 확인되지 않았습니다. 이번 지연의 정확한 내부 단계는 미확인입니다.
진행 중 수정한 준비 단계 문제
판정 및 다음 단계
외부 이벤트 → Dots 응답 → 지연된 읽기 전용 클라우드 점검 경로는 한 차례 확인했습니다. 즉시 실행, 반복 실행 신뢰성, start.sh 실행, 실제 Tailscale 단절 복구 및 새 부팅/VM 교체 후 복구는 아직 검증하지 않았습니다. #20의 자동 복구 한계를 해결했다고 처리하지 않습니다.
재시험 구독은 원래 지정한 15:23:11 KST 종료 조건으로 유지하며, 추가 이벤트는 전송하지 않았습니다. 이벤트 조회 도구를 포함한 후속 비교 fixture는 로컬 준비·시험만 했고, 무개입 관찰 중 운영 서버에는 배포하지 않았습니다.
근거: MCP Events, Scheduled app events.
abruption commentedon Oct 22, 2026
2026-10-22 상시 자동 복구 시험 개시
사용자가 읽기 전용 시험 종료 및 상시 자동 복구 시험 시작을 승인하여 구성을 전환했습니다. 자연 발생 장애를 대상으로 하며 이번 전환 과정에서 연결을 일부러 끊거나 VM 교체를 유발하지 않았습니다.
적용 및 현재 상태
dots.recovery_probe시험 3개를 비활성화했습니다. 서버에서도 active probe subscription 0건을 확인했습니다.dots.recovery_requested / target_id=dots를 종료 시각 없이 등록했습니다. Dots의 등록 확인과 서버의 active recovery subscription 1건을 대조했습니다.Linger=yes도 확인했습니다.실행 조건과 제한
get_current_recovery상태와 자기 클라우드의 스크립트 존재·실행 준비를 확인한 뒤claim_recovery를 받아야 합니다. 이미 외부 복구됐거나 감시가 오래됐으면 claim이 거부됩니다.bash /workspace/.dots-tailscale/start.sh1회입니다. claim은 장애당 1개, 1시간 간격, rolling 24시간 최대 3개이며 결과 불명확 시 재시도하지 않습니다. 120초 내 실행 지시는 Dots가 준수해야 하는 계약이며, broker가 원격 shell에서 기한을 강제하는 것은 아닙니다.externally_recovered로 닫습니다.권한 및 지속성
읽기 권한과
recovery:execute를 분리했습니다. 기존 읽기 token을 refresh해 복구 권한으로 승격할 수 없습니다. 전용 복구 플러그인에만 bounded claim/report 도구의 무인 사용 권한을 적용했습니다.새 grant의 refresh token은 회전하며 최초 승인부터 최대 90일 뒤 재인증이 필요합니다. 구독은 종료 시각 없는 자동화이지만 server grant는 유한하며 ChatGPT의 갱신에 의존합니다. 향후 갱신 성공은 계속 관찰할 항목입니다. Mac LaunchAgent는 해당 사용자 로그인 세션·Mac 전원·네트워크가 필요합니다.
검증
abruption commentedon Oct 22, 2026
사용자 요청에 따라 Dots 내부 시험 watchdog만 정상 종료했습니다. 현재 heartbeat는 stopped이며, 종료 후 새 strict SSH 접속과 Tailscale ping 성공을 확인했습니다. Tailscale·로컬 SSH와 외부 observer/relay 및 KR 복구 서비스는 유지했습니다. 기존 watchdog 로그도 보존했습니다.
내부 watchdog과 외부 복구의 역할, 재시도 예산, 중복 실행 방지, 명시적 중지 및 새 환경에서의 watchdog 시작 정책은 별도 구현 과제로 정리했습니다: #44
이번 조작은 정상 종료·연결 유지 확인이며, VM 교체 후 자동 복구 성공을 검증한 것은 아닙니다. 내부 watchdog이 stopped라는 사실만으로 네트워크 장애로 판정하지 않습니다.
abruption commentedon Oct 22, 2026
Natural outage investigation — 2026-10-23
The recovery request was not generated during the overnight outage because the observer-to-broker relay stopped delivering observations before Dots became unreachable. The broker remained running and the event subscription remained valid. Re-authenticating the relay's Tailscale SSH path restored observation delivery; three fresh failed observations then generated an event and its first callback received HTTP 200. Dots execution is still pending at the latest check.
Timeline (KST, UTC+09:00)
There were 54 healthy Mac observations after the relay's last delivered observation and before the actual Dots outage. Relay transport retry counts are not Dots recovery attempts or separate outages.
Server and transport findings
Tailscale SSH requires an additional checkfollowed by failure. Completing the user's SSH check immediately allowed server queries and resumed the existing relay without code or service changes.Gaps and proposed implementation work
한국어: Dots 장애보다 먼저 Mac→MCP 서버의 관측 전달이 멈췄고, 서버는 오래된 정상 상태만 유지했습니다. 현재 전송 경로에서는 Tailscale SSH 재인증 요구가 재현됐으며, 인증 후 전달이 즉시 재개됐습니다. 이후 실제 장애 이벤트가 한 번에 수신됐지만 아직 Dots 복구 실행 기록은 없습니다. 과거 오류 상세를 보존하지 않아 모든 전송 실패의 원인이 같았다고 단정하지 않습니다. Dots 자체가 왜 오프라인이 됐는지는 내부 접근이 복구되기 전까지 미확인입니다.
No SSH policy, keys, broker code, task instructions or production Dots startup configuration was changed in this investigation. No manual Dots message, event resend or forced restart was used. HTTP 200 means receipt, not computer execution or network recovery. Related lifecycle coordination: #44; lifecycle research: #20.
abruption commentedon Oct 23, 2026
Recovery confirmed after permission clarification — 2026-10-23
Dots performed one claimed startup attempt and external connectivity recovered. This was an operator-assisted continuation after relay re-authentication and task-instruction clarification, not a successful unattended recovery of the original overnight event from beginning to end.
Independent evidence
Intervention and scope
The restored connection verifies the claim→startup→external-recovery segment under these conditions. Relay authentication renewal, stale-delivery alerting, fully unattended scheduling and future VM-transition behavior remain open. Local research instructions/docs are preserved in commit 3f06b5c; no released package code was changed for this recovery. Related #20 and #44.
한국어: Dots의 실행 보고뿐 아니라 MCP의 claim·success·외부 복구 종료 기록과 새 SSH·ping까지 대조해 복구를 확인했습니다. 이번에는 사용자 재인증, 복구 지침 수정 및 명시적 재개 요청이 개입했습니다. 이후 Dots가 기존 start.sh를 한 번 실행해 연결을 복구한 사례이며, 전체 과정의 완전 무인 복구를 입증한 것으로 기록하지 않습니다.
abruption commentedon Oct 23, 2026
HTTPS 전달 안정화 및 실행 전 중단 보고 적용 — 2026-10-23
Draft PR #46에 연구 구현과 검증 근거를 올렸습니다. 관측 전달은 Tailscale SSH의 대화형 check 대신 전용 machine credential의 HTTPS 경로를 사용하도록 전환했습니다. 이 자격증명은 관측 입력만 허용하며 MCP 도구·claim 권한과 분리됩니다. TLS 검증을 유지하고 redirect를 거부하며 DNS를 포함한 전체 I/O에 20초 프로세스 한도를 적용했습니다.
다음 자연 장애의 무인 실행, 구독/OAuth의 장기 갱신, 실제 preflight 중단 보고 및 알림 전달은 관찰 대기입니다. 현재 단계에서 #43을 닫거나 정식 자동복구 지원으로 발표하지 않습니다.
abruption commentedon Oct 25, 2026
2026-10-25 — recovery observations and monitor relay incident
External observer logs independently confirm these recovery boundaries (KST):
The remote boot ID changed across all three outages, and the local watchdog remained stopped. This supports repeated recovery after a new boot, but does not distinguish VM replacement from reboot of the same VM. Dots reported one startup invocation and result recording per case; the protected broker claim ledger was not independently reread in this check. Durations are observer boundaries, not webhook-to-execution latency or an SLA.
The Oct 24 03:10:47–09:46:40 outage is a separate assisted case: the original three-claim rolling limit blocked recovery. Do not combine it with unattended success statistics.
Policy deployment
The deployed trial now uses 12 claims per rolling 24 hours and a 3600-second cooldown; code defaults remain 3/3600. Existing ledgers and one claim per incident are preserved. Status exposes eligibility reason/retry time, and an observed blocked-to-eligible transition can emit a distinct reminder for the same incident (maximum three reminders, never a new execution grant). At deployment, the old policy was already eligible with two claims in its rolling window, so that particular change did not establish a new unblock transition or prove a reminder delivery. Dots task instructions were updated to honor server policy.
Relay failure and recovery
At Oct 25 11:58:14, the Mac relay began reporting
transport_failed; fresh observation delivery became stale. Homebrew had replaced Python 3.15.0_1 with 3.15.1 around 11:56–11:57.lsofshowed the long-running relay still mapped the removed old runtime. A separate fresh Python process delivered the same current observation successfully and receivedsubscription_active=true.An explicitly authorized restart of only the Mac relay restored normal delivery at 12:02:36 KST:
failure_class=ok, zero consecutive failures, non-stale delivery, active subscription. No Dots/KR restart, credential reset, or firewall change was performed. Runtime replacement is the leading explanation supported by these observations; the child process's exact exception was swallowed by the existing bounded-worker error handling and was not recovered. A contemporaneous code-signing crash belonged to a different backup job and is not evidence of this relay's failure.Follow-up work remains: preserve sanitized child failure type/exit status (no credentials), detect runtime replacement, and document managed restart after interpreter upgrades. Recovery success does not imply the monitor itself needs no supervision. Implementation/evidence: #46; lifecycle: #20; coordination: #44; public support criteria: #45.
abruption commentedon Oct 25, 2026
v0.5.0 scope decision: PR #46 will deliver the current experimental research implementation, operational documentation and validated package metadata/artifacts. This issue remains open; its uncompleted acceptance criteria move to v0.6.0 rather than being marked complete. Repeated boot-change recovery is evidence for the experiment, not a guarantee of arbitrary VM replacement, general-account setup or unattended operation under every monitoring-host failure.
abruption commentedon Oct 25, 2026
v0.5.0 production broker deployment verified — 2026-10-25
Release commit:
6741383ddf1296db1f3ff31db56887e22db83580(public annotatedv0.5.0).The initial deployment preflight correctly deferred during a real Dots outage. Existing service/code remained unchanged. The external observer subsequently confirmed SSH and ping recovery at 15:38:05 KST, and the healthy observation was acknowledged before retrying deployment.
The retry applied three broker code files (
event_core.py,recovery_core.py,oauth_adapter.py) and the two scoped Caddy upstream identity-header overwrites. Installed SHA-256 values match the released sources. Before/after deployment summaries both showed fresh healthy observations, 0 open incidents, 8 claims, 1 active subscription, 0 sending deliveries. Existing configuration, authentication, subscription and recovery databases were retained.Independent post-deployment checks:
/healthz: 200; anonymous/mcp: 401; deliberately invalid OAuth client at/token: 401invalid_client, demonstrating the request reaches OAuth validation through the new proxy boundary.subscription_active=true, zero consecutive delivery failures and no stale delivery.This verifies deployment and the sampled transport/authentication paths; it is not a new production slow-request stress test or proof of future token renewal. The Dots installed package was not replaced by this broker deployment. The operator explicitly authorized merge/publication while the latest code re-review remained pending; latest security review and exact merged-commit CI passed.
abruption commentedon Oct 26, 2026
Operator observability follow-up — 2026-10-26
The maintainer's deployment now uses a dedicated target-host access log with query/header filtering, private permissions and bounded rotation. The actual Authelia file/rotations were included in the audit rather than inferring an empty journal meant no authentication records. All retained candidates were read within the expanded bounds; non-request JSON records are classified separately. One historical unrecognized text record remains explicitly unclassified, and retention/absence of compromise is not proven by these counts.
A separate, bounded root collector now publishes only target-scoped aggregate counters to an operator-readable, non-writable summary every minute. An independent Mac one-shot job reads the summary over strict-host-key SSH and uses the existing local notification credentials; credentials are not copied to the server. Authentication denial/probe/error/rate/volume indicators and collector/delivery freshness are distinct. A 180-second grace, 30-minute repeat interval and recovery-after-prior-delivered-alert rule limit noise. Incomplete or warming coverage cannot cause a recovery notification.
Live checks confirmed complete retained 5/15-minute source coverage, no active indicators, advancing summaries, and multiple successful scheduled notifier runs. No synthetic notification or deliberate attack was sent, so actual Telegram delivery of a new anomaly has not yet been exercised. Shared-host outages and SSH reauthentication can still interrupt collection and are operational limitations, not hidden healthy states.
Relay worker diagnostics are tracked in #49. Fixed error kinds/exit codes and runtime-presence metadata preserve useful failure evidence without exception text, URLs, tokens or interpreter paths. The operator relay copy is running the diagnostics with normal observation ACKs and the existing subscription. This is separate operational tooling, not a new release or general-account support claim; #43 remains open.
abruption commentedon Oct 26, 2026
v0.6.0 범위 정리: 진단 개선 PR #49는 병합됐습니다. 이 이슈 전체의 연구 완료를 의미하지 않으므로 Research 마일스톤으로 이동합니다. 장기 구독·갱신·계정별 재현 및 외부 복구 연구는 계속 유지하며, 제품화는 #44/#45(v0.7.0)에서 추적합니다.