diff --git a/.agents/references/known-issues.md b/.agents/references/known-issues.md
new file mode 100644
index 0000000..29725d3
--- /dev/null
+++ b/.agents/references/known-issues.md
@@ -0,0 +1,101 @@
+# Known Issues & Lessons Learned
+
+> **이 파일은 SSOT(Single Source of Truth)입니다.**
+> 디버깅이나 구현 전에 **반드시** 이 파일을 확인하세요.
+> 세션 종료 시 새로 발견된 이슈를 이 파일에 추가합니다.
+
+---
+
+## 포맷
+
+각 항목은 아래 형식을 따릅니다:
+
+```markdown
+### [날짜] [키워드] — 한줄 요약
+- **증상**: 무엇이 잘못되었는가
+- **원인**: 근본 원인
+- **해결**: 올바른 해결 방법
+- **주의**: 재발 방지를 위한 교훈
+```
+
+---
+
+## 공통 이슈
+
+### [2026-03-08] PowerShell curl — Invoke-WebRequest 충돌
+- **증상**: `curl` 명령이 예상과 다른 응답 형식을 반환
+- **원인**: PowerShell에서 `curl`은 `Invoke-WebRequest`의 별칭
+- **해결**: **`curl.exe`**를 명시적으로 사용
+- **주의**: HTTP 관련 모든 명령에서 `curl.exe` 사용 필수
+
+### [2026-03-08] PowerShell npm — 실행 정책 오류
+- **증상**: `npm run` 명령이 `실행 정책` 관련 오류로 실패
+- **원인**: PowerShell 스크립트 실행 정책이 제한적으로 설정됨
+- **해결**: `cmd /c npm run dev` 형식으로 cmd를 통해 실행
+- **주의**: npm 관련 명령은 항상 `cmd /c` 접두어 사용 권장
+
+---
+
+## 프로젝트별 이슈
+
+> 아래에 프로젝트 특화 이슈를 추가하세요.
+
+### [2026-03-08] Antigravity Renderer Injection — Electron 캐시 차단
+- **증상**: workbench.html, workbench-jetski-agent.html에 ``** 방식으로 HTML에 직접 삽입
+- **주의**: `ag-bridge-ports.json`도 같은 이유로 XHR 로딩 불가. 모든 렌더러 스크립트/데이터는 HTML 인라인으로 전달해야 함
+
+### [2026-03-08] Renderer 포트 디스커버리 — ag-bridge-ports.json XHR 실패
+- **증상**: `[GB Observer] Port discovery timeout after 2min` — 렌더러가 bridge 포트를 찾지 못함
+- **원인**: 렌더러 스크립트가 `./ag-bridge-ports.json`을 동기 XHR로 읽으려 하나, `vscode-file://` 프로토콜이 `.json` 파일 서빙 거부
+- **해결**: (1) 프로젝트명 해시 기반 **결정론적 포트** 사용 (`gravity_control→34332`), (2) 스크립트 생성 시 포트를 `HARDCODED_PORT=${port}`로 직접 삽입
+- **주의**: `server.listen(0)` 랜덤 포트 → 매 재시작마다 변경되어 렌더러와 불일치. 결정론적 포트는 `EADDRINUSE` 시 랜덤 폴백 필요
diff --git a/docs/devlog/2026-03-08.md b/docs/devlog/2026-03-08.md
index 30ebeae..25b9f5a 100644
--- a/docs/devlog/2026-03-08.md
+++ b/docs/devlog/2026-03-08.md
@@ -16,3 +16,4 @@
| 12 | 11:30~14:35 | 승인 로직 정밀 디버깅: IDLE→stall 전환, lastModifiedTime 구분, RPC/Commands 전수 테스트, ResolveOutstandingSteps cancel 발견 | - | 🔧 |
| 13 | 15:00~16:52 | Multi-window 격리 (v0.3.1→0.3.4): 세션 필터, per-project 포트, 등록 경쟁 조건 수정, DOM Observer 렌더러 디버깅 | - | 🔧 |
| 14 | 17:01~17:38 | **근본 원인 발견**: product.json 체크섬 불일치 → vscode-file:// 원본 캐시 서빙. 체크섬 수동 업데이트로 수정 | - | 🔧 |
+| 15 | 17:50~18:30 | **v0.3.5**: 포트 디스커버리 수정 (결정론적 포트 + 하드코딩), 인라인 스크립트 전환 (``), product.json 자동 체크섬 업데이트 | - | 🔧 |
diff --git a/extension/gravity-bridge-0.2.0.vsix b/extension/gravity-bridge-0.2.0.vsix
deleted file mode 100644
index bbd8c42..0000000
Binary files a/extension/gravity-bridge-0.2.0.vsix and /dev/null differ
diff --git a/extension/out/extension.js b/extension/out/extension.js
index ed03caa..8d7ee8d 100644
--- a/extension/out/extension.js
+++ b/extension/out/extension.js
@@ -51,6 +51,7 @@ const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const cp = __importStar(require("child_process"));
+const crypto = __importStar(require("crypto"));
// ─── File-based logging (AI can read directly) ───
function logToFile(msg) {
const ts = new Date().toISOString().replace('T', ' ').substring(0, 19);
@@ -73,6 +74,7 @@ let statusBar;
let bridgePath;
let projectName;
let isActive = false;
+let deterministicPort = 0; // derived from projectName, consistent across restarts
let watcher = null;
let commandsWatcher = null;
const sentPendingIds = new Set();
@@ -287,26 +289,44 @@ async function setupApprovalObserver() {
logToFile('[OBSERVER] workbench.html patched (needs reload)');
}
// Also patch workbench-jetski-agent.html (Antigravity's actual entry point!)
+ // IMPORTANT: vscode-file:// protocol does NOT serve custom .js files,
+ // so we INLINE the script content directly into the HTML.
const scriptDir = path.dirname(scriptPath);
const jetskiHtml = path.join(scriptDir, 'workbench-jetski-agent.html');
- const scriptBasename = path.basename(scriptPath);
try {
if (fs.existsSync(jetskiHtml)) {
let html = fs.readFileSync(jetskiHtml, 'utf8');
- if (!html.includes(scriptBasename)) {
- html = html.replace('