Skip to content

Commit 218d973

Browse files
committed
코드정리
1 parent f69af6b commit 218d973

34 files changed

Lines changed: 3 additions & 5420 deletions

README.ko.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ Pyodide Workers
222222
| `MachineJournal` | WAL: 유휴에 스스로 체크포인트해, 강제종료된 탭도 마지막 커밋으로 부활 |
223223
| `MachineJail` | 권한 감옥: `permissions{net, clipboard, home, workers}`를 2단 집행. 협조 파이썬 초크포인트 + 브라우저 벽(감옥 컨텍스트의 `connect-src` CSP가 비허용 host 차단, 감옥 코드가 `import js`로 우회해도 무력) |
224224
| `GpuCompute` / `GpuArray` / `GpuBridge` | f32 대규모 선형대수를 WebGPU 컴퓨트로 오프로드: 잔류 핸들(업로드 1회, GPU 위에서 `matmul` / `map` / `binary` / `transpose` / `reduce` 체이닝, 다운로드 1회, 공유메모리 타일드 커널). 전체 파이프라인이 GPU에 남는다: `matmul -> relu -> sum`(loss), `x.transpose() @ dy`, 잔차 `(A@B) + C`. `Runtime.enableGpu()`가 파이썬에 배선(`pyprocGpu.matmul`이 numpy 배열을). 실 GPU에서 WASM numpy 대비 ~127배 실측. f32 한정(WGSL은 f64 없음), 창 있는 브라우저 + GPU 필요 |
225-
| `BrowserControl` | MV3 확장 offscreen에서 파이썬이 브라우저를 조작: `Runtime.enableBrowserControl()` -> `install()` -> `pyprocBrowser.tab(url, mode)`. Playwright급 표면: 항법(`navigate` / `reload` / `back` / `forward`), 입력(`click` / `doubleClick` / `rightClick` / `hover` / `type` / `fill` / `press` / `select`), 조회·추출(`text` / `attr` / `value` / `exists` / `count` / `texts` / `boundingBox` / `title` / `url` / `content`), 대기(`waitFor` / `waitForFunction`), 캡처·에뮬레이션(`screenshot` / `pdf` / `setViewport` / `setUserAgent` / `setHeaders` / `emulateMedia` 다크모드 / `setTimezone` / `setOffline` / `setGeolocation` / `setLocale`), 다운로드(`enableDownloads` / `waitForDownload`로 무엇이 다운로드되는지 관측), 콘솔(`enableConsole` / `consoleLogs` / `waitForConsole`로 페이지 로그·미처리 에러 캡처), 접근성(`accessibilityTree`로 페이지를 role/name 시맨틱으로 회수 = 에이전트 의미 네비게이션), 쿠키(`cookies` / `setCookie` / `clearCookies` / `deleteCookie`), 파일(`upload`), 다이얼로그(`setDialogHandler`가 alert/confirm/prompt 자동 응답), 네트워크(`route`로 CDP Fetch 요청 차단·목킹·변조·붙잡기, 붙잡은 요청은 `pendingRequests` + `continueRequest` / `fulfillRequest` / `abortRequest`로 요청마다 Python이 결정, `waitForResponse` / `requests` / `responseBody`로 응답 관측·바디 캡처), 프레임(`frames` / `frame`으로 iframe 내부 드릴다운: same-origin은 isolated world, cross-origin OOPIF는 그 타깃에 attach). 포인터 op는 대상을 자동 스크롤한다. 두 mode: `script`(chrome.scripting, 스텔스, `navigator.webdriver` 미점화)와 `debugger`(chrome.debugger CDP, 신뢰 입력 `isTrusted=true`, 캡처·에뮬·다이얼로그·네트워크 전 표면). 한 탭에 대한 영속 세션 핸들. 탭이 외부 종료되면 이후 op가 `SessionLost` 예외. 프로세스 OS 융합: `routeBrowserWorker`(offscreen 릴레이) + `installBrowserWorker`(워커 측)로 Pyodide 워커 N개가 각자 독립 인터프리터(N GIL)로 자기 세션을 몬다 = Playwright가 못 하는 차별점. 서비스워커 절반은 별도 subpath `pyproc/browser-control-host`. Chromium 확장 전용 |
226225
| `bootSession` / `Session` / `openMachine` | 세션 부활 + 이동 가능한 `.pymachine` 이미지: 결정적 리플레이 + 사용자 델타, OPFS 영속(`save` / `load`) 또는 한 파일 내보내기(`exportImage` / `openMachine`) |
227226
| `WheelCache` | 오프라인 / 재다운로드 0 패키지 설치용 wheel / OPFS 캐시 |
228227
| `PyProc` | 프로세스 OS 커널: 스냅샷-fork 스폰, `map` / `mapArray` 병렬, 수명주기(`kill` / `signal` / respawn), `fork(2)`(살아있는 프로세스 복제, 변수·배열이 실린다), 흐름 IPC(`pipe` / `lock` / `semaphore` / `shm`: SAB 링버퍼 파이프, 진짜 블로킹 read + backpressure) |

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ Capabilities are opt-in - turn on only what you need, and consume the capability
222222
| `MachineJournal` | Write-ahead log: the machine checkpoints itself while idle, so a crashed tab still boots back into its last commit |
223223
| `MachineJail` | Permission jail: `permissions{net, clipboard, home, workers}` enforced in two tiers, a cooperative Python chokepoint plus the browser's own wall (a `connect-src` CSP on the jail context blocks disallowed hosts even if the jailed code tries `import js`) |
224224
| `GpuCompute` / `GpuArray` / `GpuBridge` | Offload large f32 linear algebra to WebGPU compute: a residency handle (upload once, chain `matmul` / `map` / `binary` / `transpose` / `reduce` on the GPU, download once) with a shared-memory tiled kernel. Full pipelines stay GPU-resident: `matmul -> relu -> sum` (loss) and `x.transpose() @ dy` / residual `(A@B) + C`. `Runtime.enableGpu()` wires it into Python (`pyprocGpu.matmul` on numpy arrays). Measured ~127x vs WASM numpy on a real GPU; f32 only (WGSL has no f64), needs a windowed browser with a GPU |
225-
| `BrowserControl` | Drive the browser from Python inside an MV3 extension offscreen document: `Runtime.enableBrowserControl()` -> `install()` -> `pyprocBrowser.tab(url, mode)`. Playwright-class surface: navigation (`navigate` / `reload` / `back` / `forward`), input (`click` / `doubleClick` / `rightClick` / `hover` / `type` / `fill` / `press` / `select`), query/extract (`text` / `attr` / `value` / `exists` / `count` / `texts` / `boundingBox` / `title` / `url` / `content`), waiting (`waitFor` / `waitForFunction`), capture/emulation (`screenshot` / `pdf` / `setViewport` / `setUserAgent` / `setHeaders` / `emulateMedia` dark mode / `setTimezone` / `setOffline` / `setGeolocation` / `setLocale`), downloads (`enableDownloads` / `waitForDownload` observe what is being downloaded), console (`enableConsole` / `consoleLogs` / `waitForConsole` capture page logs and uncaught errors), accessibility (`accessibilityTree` reads the page as role/name semantics for agent navigation), cookies (`cookies` / `setCookie` / `clearCookies` / `deleteCookie`), files (`upload`), dialogs (`setDialogHandler` auto-answers alert/confirm/prompt), network (`route` blocks / mocks / modifies / holds requests via CDP Fetch; held requests are decided per-request from Python via `pendingRequests` + `continueRequest` / `fulfillRequest` / `abortRequest`; `waitForResponse` / `requests` / `responseBody` observe responses and capture bodies), frames (`frames` / `frame` drill into an iframe: same-origin via an isolated world, cross-origin OOPIF by attaching to its target). Pointer ops auto-scroll the target into view. Two modes: `script` (chrome.scripting, stealth, no `navigator.webdriver`) and `debugger` (chrome.debugger CDP, trusted input `isTrusted=true`, full capture/emulation/dialog/network). Persistent session handle over one tab; a tab closed externally raises `SessionLost`. Process-OS fusion: `routeBrowserWorker` (offscreen relay) + `installBrowserWorker` (worker side) let N Pyodide workers each drive their own session with an independent interpreter (N GILs), the differentiator Playwright cannot match. The service worker half is a separate subpath `pyproc/browser-control-host`. Chromium extension only |
226225
| `bootSession` / `Session` / `openMachine` | Session revival and portable `.pymachine` images: deterministic replay plus user delta, persisted to OPFS (`save` / `load`) or exported as one file (`exportImage` / `openMachine`) |
227226
| `WheelCache` | Wheel / OPFS cache for offline, zero-redownload package installs |
228227
| `PyProc` | Process OS kernel: snapshot-fork spawn, `map` / `mapArray` parallelism, lifecycle (`kill` / `signal` / respawn), `fork(2)` (clone a live process, its variables and arrays travel), and flow IPC (`pipe` / `lock` / `semaphore` / `shm`: SAB ring-buffer pipes with real blocking read and backpressure) |

docs/consuming/contract.md

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,7 @@ await navigator.serviceWorker.register("/pyprocSw.js?coi=1");
5656

5757
**가상 오리진 경계 (정직한 벽)**: SW 합성 응답이라 진짜 오리진과 다르다. (1) `Set-Cookie`는 스트립된다(쿠키 세션 불가 = 토큰 방식 사용). (2) WebSocket 업그레이드는 가로채지 않는다(ASGI dispatch는 HTTP 요청/응답 단위). (3) 스트리밍/SSE는 축적 후 일괄 응답이다(청크 스트림 아님). (4) 엔드포인트는 `async def` 강제(동기 dispatch 없음). 부활(저널/세션/openMachine) 후에는 파일 핸들·DB 커넥션 같은 프로세스 자원이 되살아나지 않는다: 리플레이+델타는 파이썬 힙 상태를 복원하지 그 밖의 OS 자원을 복원하지 않으므로, 소비자는 부팅 훅(`boot.py` 또는 `Init`)에서 그런 자원을 재개설한다.
5858

59-
subpath export: `pyproc/runtime`, `pyproc/reactive`, `pyproc/syscall-bridge`, `pyproc/process-os`, `pyproc/worker`, `pyproc/browser-control-host`. **src 내부 경로 deep import 금지** (내부 파일 배치는 릴리즈 간 바뀔 수 있다. 실제로 v0.0.3에서 레이어 폴더로 재배치됐고 subpath 이름은 불변이었다).
60-
61-
### 브라우저 컨트롤 확장 (BrowserControl)
62-
63-
`BrowserControl`은 MV3 확장 안에서만 성립한다(offscreen document = 런타임 호스트, service worker = 권한 소유). 코어의 "단일 import + 버전 핀"과 달리, 확장은 파일이 확장 패키지 안에 물리적으로 있어야 하고 manifest 키의 상당수가 제품 결정이 아니라 pyproc 런타임 요구다. 조립 레퍼런스(실 src를 import하는 최소 픽스처): `tests/browser/runExtension.mjs` + `tests/browser/extensionFixture/`.
64-
65-
**두 절반(같은 핀 강제)**:
66-
- offscreen: `boot()` + `Runtime.enableBrowserControl()` + `install()` (능력, index import). JSPI 필요 = `rt.runAsync` 경로.
67-
- service worker: `openBrowserControlHost()` (subpath `pyproc/browser-control-host`).
68-
- 두 절반은 `browserControlProtocol`의 버전된 메시지로 통신하고(현재 `PROTOCOL_VERSION=2`), `install()`이 핸드셰이크로 버전 불일치를 loud fail한다. **두 절반은 반드시 같은 pyproc 핀**이어야 한다(다른 핀 = 프로토콜 드리프트 = 런타임 파손).
69-
70-
**프로세스 OS 융합(워커 N = 세션 N, 독립 GIL N)**: `install()`은 offscreen 메인 인터프리터를 배선한다. N개 워커가 각자 파이썬으로 브라우저를 몰려면(진짜 병렬), dedicated Worker엔 `chrome.*`이 없으므로(제약 A) offscreen이 라우터가 된다. 워커 측은 `installBrowserWorker(py)`(그 워커 파이썬의 `_pyprocBrowserSend`를 offscreen postMessage로 배선 + `pyprocBrowser` 모듈 실행), offscreen 측은 스폰한 워커마다 `routeBrowserWorker(worker)`(워커 op를 SW 호스트로 릴레이). 워커는 offscreen(COI)에서 스폰돼 crossOriginIsolated를 상속해야 SAB/JSPI(run_sync)가 산다. 파이썬 연산은 워커별 GIL로 물리 병렬, 브라우저-op은 SW 단일 CDP 큐로 직렬(정직한 천장: N배 연산 병렬 + 1배 op 레이트). 실측: 실 src 픽스처가 Pyodide 워커를 이 경로로 몰아 검증.
71-
72-
**조작 표면(`pyprocBrowser.tab(url, mode)` -> `BrowserTab`)**: 항법(navigate/reload/back/forward), 입력(click/doubleClick/rightClick/hover/type/fill/press/select, 좌표 입력은 자동 스크롤 내장 + scrollIntoView/upload), 조회·추출(evaluate/text/html/attr/value/exists/count/texts/boundingBox/title/url/content), 대기(waitFor/waitForFunction), 캡처·에뮬레이션(screenshot/pdf/setViewport/setUserAgent/setHeaders/emulateMedia 다크모드·setTimezone·setOffline·setGeolocation 좌표 스푸핑·setLocale 언어 스푸핑), 다운로드 관측(enableDownloads/waitForDownload = 무엇이 다운로드되는지 파일명·URL 회수, 저장 경로 지정은 browser-level이라 미지원), 콘솔·에러 캡처(enableConsole/consoleLogs/waitForConsole = 페이지 console.* + 미처리 예외 관측), 접근성 트리(accessibilityTree = role/name 시맨틱으로 페이지 회수), 쿠키(cookies/setCookie/clearCookies/deleteCookie), 다이얼로그(setDialogHandler/lastDialog = alert/confirm/prompt 세션 정책 자동 응답), 네트워크(route/unroute = CDP Fetch 차단·정적 응답·요청 변조·붙잡기, 붙잡은 요청의 콜백형 결정 pendingRequests/continueRequest/fulfillRequest/abortRequest, waitForResponse/requests/responseBody = 응답 관측·바디 캡처), 프레임(frames/frame = iframe 내부 드릴다운. same-origin은 isolated world, cross-origin OOPIF는 chrome.debugger.getTargets에서 이 페이지 iframe src로 스코프해 targetId로 직접 attach = 둘 다 지원). 조작 계열은 핸들을 돌려 체이닝되고, 조회 계열은 JSON-값을 돌려준다(structured clone 경계라 PyProxy 아님). mode="debugger"는 CDP 신뢰 입력(isTrusted=true) + 캡처·에뮬·다이얼로그·네트워크 전 표면, mode="script"는 chrome.scripting 합성 입력(isTrusted=false)이고 CDP 전용 표면은 미지원 예외다. CDP 전용 표면은 추가 권한이 아니라 `debugger`가 여는 CDP Page/Network/Emulation/Fetch/DOM 도메인으로 대행한다. 전 표면은 attempts 게이트(1-16) + 실 src 픽스처로 브라우저 실측 통과(정본 타입: `index.d.ts`의 `BrowserTab`).
73-
74-
**manifest 필수 키(pyproc 런타임 요구, 제품이 못 바꾸는 계약)**:
75-
76-
|| 이유 |
77-
| --- | --- |
78-
| `cross_origin_embedder_policy: require-corp` + `cross_origin_opener_policy: same-origin` | crossOriginIsolated = 프로세스 OS(SAB/워커) 전제 |
79-
| `content_security_policy.extension_pages: "... 'wasm-unsafe-eval' ..."` | 원격 코드 금지 하 Pyodide WASM 구동 조건 |
80-
| `permissions: offscreen, debugger, scripting, tabs` | 능력이 쓰는 chrome API(debugger 모드 = CDP 신뢰입력, script 모드 = chrome.scripting, 탭 수명) |
81-
| `permissions: declarativeNetRequest` | iframe 역전(고정 화면) 헤더 제거. 조작만 쓰면 생략 가능 |
82-
| `permissions: storage` | 세션 메타 storage.session write-through(SW 소멸 후 재attach 복구) |
83-
| `permissions: contentSettings` | setGeolocation 권한 부여. CDP Browser.grantPermissions가 browser-level이라 막혀 chrome.contentSettings.location로 우회. 지오로케이션 안 쓰면 생략 가능 |
84-
| `minimum_chrome_version: 116` | offscreen API 하한 |
85-
86-
제품 결정(소비자 몫): `name`/`description`/`host_permissions` 범위/웹스토어 메타. offscreen이 자기 확장 자산을 로드하는 경로엔 `web_accessible_resources`가 불필요하다(same-origin 확장 문서, 픽스처 실측 확인).
87-
88-
**vendoring(SHA-핀 단일 import로는 부족)**: 확장은 번들러 없이 상대 경로로 로드되므로, pyproc `src` 트리를 구조 보존해 확장에 vendoring한다(offscreen이 `boot()`로 워커를 스폰하면 `worker.js`가 같은 폴더 계약을 확장 안으로 끌고 온다). vendor Pyodide 코어도 확장에 번들(`npm run fetch:engine`). 번들 소비자(Vite)는 subpath export로, 언번들 확장은 구조 보존 vendoring으로 도달한다.
89-
90-
**offscreen 격리 vs iframe 역전(Phase 2)**: 프로세스 OS는 COI(COEP require-corp)를 요구하는데 cross-origin iframe 역전(고정 화면)은 credentialless를 강제해 쿠키/sandbox가 막힌다(실측 3중 확증). 그래서 런타임(COI offscreen)과 iframe 셸(non-COI 문서)은 **다른 문서로 분리**한다. iframe 셸 UI는 제품 몫이고 pyproc은 헤더 제거 프리미티브만 기여한다.
59+
subpath export: `pyproc/runtime`, `pyproc/reactive`, `pyproc/syscall-bridge`, `pyproc/process-os`, `pyproc/worker`. **src 내부 경로 deep import 금지** (내부 파일 배치는 릴리즈 간 바뀔 수 있다. 실제로 v0.0.3에서 레이어 폴더로 재배치됐고 subpath 이름은 불변이었다).
9160

9261
- 타입은 동봉된 `index.d.ts`가 계약이다.
9362
- 엔진 내부(`HEAPU8`, `Runtime.raw` 등)를 직접 만지지 않는다. `raw`는 탈출구이고 계약 밖이다.

0 commit comments

Comments
 (0)