diff --git a/agent-ops/rules/project/domain/testing/rules.md b/agent-ops/rules/project/domain/testing/rules.md index 182d594..894dfcb 100644 --- a/agent-ops/rules/project/domain/testing/rules.md +++ b/agent-ops/rules/project/domain/testing/rules.md @@ -1,14 +1,14 @@ --- domain: testing -last_rule_review_commit: 01bef3dc933e225b09d0f348aab6b0097275a4d8 -last_rule_updated_at: 2026-05-21 +last_rule_review_commit: 3b9f37076a396370f1c7043d7fa92e6f0a006031 +last_rule_updated_at: 2026-05-27 --- # testing ## 목적 / 책임 -작업 완료 후 어떤 테스트와 bin shell 사용자 흐름 검증을 거쳐야 하는지 정리한다. 테스트 파일을 바꿨는지가 아니라, 변경 작업이 어떤 사용자 실행 파이프라인에 닿았는지를 기준으로 검증 범위를 정한다. +작업 완료 후 어떤 테스트와 bin shell 사용자 흐름 검증을 거쳐야 하는지 정리한다. 테스트 파일을 바꿨는지가 아니라, 변경 작업이 어떤 사용자 실행 파이프라인에 닿았는지를 기준으로 검증 범위를 정한다. 대상 host에서 사용자가 복사해 실행하는 bootstrap/install command의 기본 UX 기준도 이 도메인에서 다룬다. ## 포함 경로 @@ -37,6 +37,7 @@ last_rule_updated_at: 2026-05-21 - Web Portal verify — `apps/web` 변경 시 `npm run verify --prefix apps/web` 기준으로 TypeScript check와 production build를 확인한다. - full-cycle 실제 구동 — 비효율적이어도 관련 사용자 명령과 실행 cycle을 한 번씩 실제 entrypoint로 통과시키는 검증이다. - 실제 외부 CLI 검증 — `claude`, `antigravity`, `codex`, `opencode`처럼 외부 CLI 설치와 계정/환경이 필요한 기준 profile을 실제 호출하는 검증이다. +- one-line bootstrap/install UX — Node, OTO, specialized agent, Control Plane enrollment처럼 사용자가 대상 host에서 복사해 실행하는 연결/설치 명령의 사용자 경험 기준이다. ## 유지할 패턴 @@ -50,6 +51,9 @@ last_rule_updated_at: 2026-05-21 - 보조 E2E smoke는 mock adapter와 임시 설정/포트를 사용해 외부 CLI 의존성 없이 수행한다. - 보조 E2E smoke에서는 최소한 node 등록, `/nodes` 확인, console 메시지 전송, delta/message 출력, complete event를 확인한다. - full-cycle 실제 구동에서는 startup/register, foreground run, session 변경, background run, terminate-session, status, 관련 routing/cancel/timeout/persistent session cycle을 실제 entrypoint로 한 번씩 통과시킨다. +- one-line bootstrap/install command는 Jenkins agent 연결처럼 간결해야 한다. 사용자에게 전달하는 명령은 artifact/bootstrap URL이 완성된 한 줄이어야 하며, 사용자가 직접 바꾸는 값은 token 같은 단일 positional 값만 둔다. +- one-line bootstrap/install command의 Edge 주소, artifact 주소, target, platform, config path 같은 값은 작업자/Edge/Control Plane이 미리 굽거나 완성해서 제공한다. 사용자 기본 경로에서 `IOP_*=` 같은 named environment parameter나 여러 주소 조합을 직접 입력하게 하지 않는다. +- field Node bootstrap의 사용자 명령은 `curl -fsSL <완성된-bootstrap-url> | bash -s ` 형태를 기준으로 한다. 다른 bootstrap/enrollment 작업에서도 같은 수준의 단일 token UX를 우선 적용하고, 예외가 필요하면 사용자에게 먼저 확인한다. - 상세 수행 절차와 기능별 체크리스트는 `agent-ops/skills/project/e2e-smoke/SKILL.md`를 따른다. - `make test-e2e`, `scripts/e2e-smoke.sh`, `scripts/e2e-openai-ollama.sh`는 보조 smoke 명령이다. 실행할 수 있으면 보조 확인으로 기록하되, bin shell 사용자 흐름을 대체하지 않는다. - `bin/build/field-binaries.sh` 변경 시 최소 현재 host target build를 실행하고 산출물 위치와 checksum 생성을 확인한다. @@ -116,4 +120,5 @@ terminated session default node=test-node - 관련 작업 후 full-cycle 실제 구동을 비용이 크다는 이유만으로 생략하지 않는다. - 보조 E2E smoke를 외부 CLI 설치, 로그인, 네트워크 계정 상태에 의존하게 만들지 않는다. - 검증을 위해 기본 `configs/*.yaml`을 임시값으로 오염시키지 않는다. 임시 설정 파일이나 환경 변수 override를 사용한다. +- 사용자 기본 bootstrap/install 안내에 `IOP_ARTIFACT_BASE_URL=...`, `IOP_EDGE_ADDR=...`, `IOP_NODE_TOKEN=...` 같은 named environment parameter를 요구하지 않는다. 이런 값은 작업자용 디버그/override 경로로만 분리한다. - 필수 검증을 실행하지 못했는데 조용히 생략하지 않는다. diff --git a/agent-ops/rules/project/rules.md b/agent-ops/rules/project/rules.md index 3010ac5..9a0223a 100644 --- a/agent-ops/rules/project/rules.md +++ b/agent-ops/rules/project/rules.md @@ -54,6 +54,7 @@ - 테스트는 변경 범위에 맞춰 `go test ./...` 또는 대상 패키지 테스트를 실행한다. - 사용자 실행 파이프라인에 닿는 작업을 한 경우, 작업 완료 후 `agent-ops/rules/project/domain/testing/rules.md`의 검증 기준을 따른다. - field 테스트 환경 또는 one-line bootstrap 작업은 `docs/deploy-dev.md`의 Field 테스트 환경 라우팅과 활성 Milestone `Field Bootstrap UX와 테스트 포트 정비`를 먼저 확인한다. +- Node, OTO, specialized agent, Control Plane enrollment 등 사용자가 대상 host에서 실행하는 bootstrap/install command 작업은 `agent-ops/rules/project/domain/testing/rules.md`의 one-line bootstrap UX 기준을 따른다. - code-server 기반 field 테스트 포트는 원격 `ssh toki@toki-labs.com`의 `~/docker/services/code-server/compose/docker-compose.yml`에서 관리한다. 기준 host port는 web/dev `13000-13099`, artifact/bootstrap HTTP `18080`, OpenAI-compatible HTTP `18081`, Edge-Node transport `19090`, Edge metrics `19092`, OTO/specialized agent transport `19190`이다. - 상세 DB schema, event schema, permission/policy/audit model, federation, mTLS 구현 세부, Portal UI 세부 기획은 각 작업에서 별도로 결정한다. @@ -86,4 +87,5 @@ - 사용자 실행 파이프라인 검증, bin shell 사용자 흐름, 메시지 2회 왕복, edge command 응답, 보조 E2E smoke, full-cycle 실제 구동, `bin/edge.sh`/`bin/node.sh` 통합 테스트: `agent-ops/skills/project/e2e-smoke/SKILL.md` - field 테스트 포트, artifact/bootstrap HTTP, one-line Node bootstrap, code-server compose 기반 외부 테스트 환경: `docs/deploy-dev.md`와 활성 Milestone `agent-roadmap/phase/serving-routing-optimization/milestones/field-bootstrap-test-port-readiness.md` +- bootstrap/install UX, Agent Bootstrap, OTO 등록, Control Plane enrollment처럼 사용자가 대상 host에서 복사해 실행하는 명령을 설계하거나 바꿀 때: `agent-ops/rules/project/domain/testing/rules.md`의 one-line bootstrap UX 기준과 `docs/deploy-dev.md`의 field bootstrap 기준을 확인한다. - 반복 작업이 확인되면 `agent-ops/skills/project//SKILL.md`를 생성하고 이 표에 등록한다. diff --git a/agent-roadmap/phase/serving-routing-optimization/milestones/field-bootstrap-test-port-readiness.md b/agent-roadmap/phase/serving-routing-optimization/milestones/field-bootstrap-test-port-readiness.md index 5e613f7..1540ecf 100644 --- a/agent-roadmap/phase/serving-routing-optimization/milestones/field-bootstrap-test-port-readiness.md +++ b/agent-roadmap/phase/serving-routing-optimization/milestones/field-bootstrap-test-port-readiness.md @@ -29,6 +29,7 @@ code-server 컨테이너는 외부 테스트용 web/bootstrap, Node transport, O - IOP field 테스트용 포트를 web/bootstrap HTTP, Node Edge transport, OTO/specialized agent transport 용도로 분리해 재부팅 후 바로 사용할 수 있게 한다. - Edge 쪽 build artifact 위치와 URL 규칙을 정하고, Apple Silicon Node를 우선 대상으로 한 one-line bootstrap UX를 만든다. - bootstrap 명령은 바이너리 다운로드, checksum 또는 버전 확인, 임시 config 생성, `iop-node serve` 실행까지 한 줄 수준으로 이어지는 것을 목표로 한다. +- 사용자에게 보이는 bootstrap 명령은 artifact/bootstrap URL이 완성된 상태로 제공되어야 하며, 사용자가 직접 바꾸는 값은 token 값 하나뿐이다. `IOP_*=` 같은 named parameter는 사용자 기본 경로에 두지 않는다. - 이번 Milestone은 테스트 환경과 bootstrap UX를 다루며, Control Plane 기반 장기 enrollment/credential 관리와 OTO agent 본격 구현은 후속 Phase/Milestone에서 다룬다. ## 기능 @@ -39,7 +40,7 @@ field 테스트를 매번 수동 터널과 임시 명령 조합으로 만들지 - [x] [compose-ports] code-server compose가 field 테스트용 web/bootstrap, Node transport, OTO/specialized agent 포트를 외부에 노출한다. 검증: `docker compose config`에서 `18080`, `18081`, `19090`, `19190` 계열 포트 매핑이 확인된다. - [x] [artifact-layout] Node field build 산출물의 고정 위치와 URL 규칙이 정리되어 있다. 검증: Apple Silicon용 `iop-node`를 정해진 URL에서 다운로드할 수 있다. -- [x] [one-line-node] 사용자가 한 줄 명령으로 Apple Silicon Node를 다운로드하고 Edge에 접속할 수 있다. 검증: Mac 테스트 환경에서 command 한 줄 실행 후 Edge에서 node registration을 확인한다. +- [x] [one-line-node] 사용자가 token 값 하나만 넣은 한 줄 명령으로 Apple Silicon Node를 다운로드하고 Edge에 접속할 수 있다. 검증: Mac 테스트 환경에서 `curl -fsSL <완성된-bootstrap-url> | bash -s ` 형태의 command 한 줄 실행 후 Edge에서 node registration을 확인한다. - [x] [serve-lifecycle] `edge serve`가 field bootstrap에 사용할 node/openai listener를 안정적으로 유지한다. 검증: `edge serve --config ` 실행 후 Node registration과 `/v1/models` 호출이 통과한다. - [x] [runbook] field bootstrap runbook에 직접 포트 방식과 터널 fallback 방식이 구분되어 있다. - [x] [llm-test-runbook] LLM/작업자가 사용자 직접 테스트를 준비하고 실패 지점을 분리할 수 있는 상세 runbook이 문서화되어 있다. 검증: `docs/deploy-dev.md`에 포트 확인, Edge config, artifact 생성, HTTP 노출, Mac one-line bootstrap, OpenAI-compatible 확인, 실패 시 확인 순서가 있다. @@ -64,10 +65,11 @@ field 테스트를 매번 수동 터널과 임시 명령 조합으로 만들지 ## 작업 컨텍스트 -- 관련 경로: `docs/deploy-dev.md`, `bin/build/field-binaries.sh`, `bin/edge.sh`, `apps/edge/cmd/edge`, `apps/edge/internal/bootstrap`, `apps/edge/internal/input`, `apps/edge/internal/transport`, 원격 `~/docker/services/code-server/compose/docker-compose.yml` +- 관련 경로: `docs/deploy-dev.md`, `docs/field-bootstrap-work-guide.md`, `bin/build/field-binaries.sh`, `bin/edge.sh`, `apps/edge/cmd/edge`, `apps/edge/internal/bootstrap`, `apps/edge/internal/input`, `apps/edge/internal/transport`, 원격 `~/docker/services/code-server/compose/docker-compose.yml` - 표준선(선택): Edge-Node transport는 TCP proto-socket을 유지하고, HTTP는 artifact/bootstrap과 OpenAI-compatible 입력 표면에만 사용한다. - 표준선(선택): 외부 테스트 포트는 기존 code-server compose의 안전 remap 관례를 따라 host 충돌 포트를 피하고, 재부팅 타이밍은 사용자가 결정한다. - 표준선(선택): bootstrap UX는 Jenkins agent처럼 Edge가 command를 제시하고 대상 host가 실행하는 흐름을 목표로 하되, 초기 field 단계에서는 static artifact URL과 one-time-ish token/config로 시작한다. +- 표준선(선택): 사용자용 bootstrap command는 `curl -fsSL <완성된-bootstrap-url> | bash -s ` 형태를 기준으로 한다. artifact URL은 작업자/Edge가 완성해 제공하고, 사용자가 치환하는 값은 token 하나만 둔다. - 선행 작업: Ollama 실테스트와 후속 안정화 - 진행 기록: 원격 `~/docker/services/code-server/compose/docker-compose.yml`에 `18080:18080`, `18081:8080`, `19190:9190`을 추가하고 기존 `19090:9090`, `19092:9092`를 역할 주석으로 정리했다. `/usr/local/bin/docker compose config --quiet` 검증은 통과했으며, 실제 포트 적용은 사용자가 정한 code-server compose 재기동 시점 이후 확인한다. - 진행 기록: `agent-ops/rules/project/rules.md`에서 field 테스트 환경 작업을 `docs/deploy-dev.md`와 이 Milestone으로 라우팅하도록 보강했고, `docs/deploy-dev.md`에 code-server compose 원본, 기준 포트, 직접 포트/터널 fallback, Apple Silicon `darwin/arm64` 기준을 기록했다. @@ -78,3 +80,14 @@ field 테스트를 매번 수동 터널과 임시 명령 조합으로 만들지 - 후속 작업: Agent Bootstrap과 OTO 등록, Control Plane 기반 enrollment - 진행 기록: Mac에서 bootstrap artifact 다운로드와 Node 재접속을 반복 확인했고, Edge 로그에서 `node-silicon-ollama` registration, `/v1/models`, OpenAI-compatible streaming delta, Cline XML tool protocol 통과를 확인했다. - 확인 필요: archive 이동 승인 + +## 다음 세션 재개 메모 + +- 사용자 정정 사항: Edge-Node 실사용 연결에 외부 공개가 필요한 포트는 `19090` 하나다. `18080`은 bootstrap shell script, `iop-node` binary, checksum을 내려받는 artifact HTTP 포트일 뿐이며 Edge-Node 런타임 포트가 아니다. +- 최종 방향: 외부 공개는 `toki-labs.com:19090`만 유지한다. bootstrap/artifact 전달은 내부망, front/control-plane, CI artifact, 또는 임시 로컬 HTTP처럼 별도 채널로 처리하고, 생성되는 `node.yaml`의 `transport.edge_addr`만 `toki-labs.com:19090`이 되게 한다. +- 다음 테스트에서는 `curl http://toki-labs.com:18080/... | bash` 형태를 기본 안내로 쓰지 않는다. 외부 18080을 열지 않을 계획이면 bootstrap script는 내부 접근 가능한 주소에서 받고, script 기본값으로 `toki-labs.com:19090`을 굽는다. +- 사용자용 명령은 반드시 artifact URL이 완성된 `curl -fsSL <완성된-bootstrap-url> | bash -s ` 형태로 제공한다. 사용자가 직접 넣는 값은 token 하나뿐이며 `IOP_ARTIFACT_BASE_URL=...`, `IOP_EDGE_ADDR=...`, `IOP_NODE_TOKEN=...` 같은 named parameter를 요구하지 않는다. +- 현재 임시 live artifact version은 `field-live-20260527-19ddd9bd38b7`, token은 `iop-field-20260527-7fd4c675`, node id는 `node-silicon-ollama`, model은 `gemma4:26b`였다. 이전 테스트 중 bootstrap script 기본값을 한 번 `ARTIFACT_BASE_URL=http://toki-labs.com:18080`, `EDGE_ADDR=toki-labs.com:19090`로 재생성했으나, 이는 외부 18080까지 쓰는 형태라 최종 방향과 다르다. +- 재개 시 먼저 stale process를 확인한다: `ps -ef | rg 'python3 -m http.server 18080|go run ./apps/edge/cmd/edge|/tmp/go-build.*/edge serve|iop-edge serve'`. 필요하면 임시 edge/artifact server를 정리하고 새 설정으로 다시 띄운다. +- 권장 재테스트 형태: artifact server는 내부에서만 접근 가능한 주소로 열고 `ARTIFACT_BASE_URL=`, `BOOTSTRAP_EDGE_ADDR=toki-labs.com:19090`으로 Apple Silicon bootstrap을 생성한다. 사용자에게 주는 실행 명령은 artifact 접근 채널에 맞춰 완성된 URL로 제공하되, token은 명령 마지막 positional value 하나로만 받는다. +- 작업 가이드 문서: `docs/field-bootstrap-work-guide.md` diff --git a/bin/build/field-binaries.sh b/bin/build/field-binaries.sh index f2eb228..3cafce3 100755 --- a/bin/build/field-binaries.sh +++ b/bin/build/field-binaries.sh @@ -22,9 +22,9 @@ Environment: VERSION= release version label COMMIT= commit label BUILD_DATE= build date label - ARTIFACT_BASE_URL= default bootstrap artifact base URL - BOOTSTRAP_EDGE_ADDR= default Edge address written to node.yaml - BOOTSTRAP_NODE_TOKEN= default Node registration token +ARTIFACT_BASE_URL= default bootstrap artifact base URL +BOOTSTRAP_EDGE_ADDR= default Edge address written to node.yaml +BOOTSTRAP_NODE_TOKEN= optional fallback token baked into bootstrap script CGO_ENABLED=0 Go CGO setting GOFLAGS="-trimpath" extra go build flags LDFLAGS="-s -w" linker flags @@ -88,7 +88,7 @@ write_node_bootstrap() { local script="$bootstrap_dir/node-$target_dir.sh" local default_base_url="${ARTIFACT_BASE_URL:-"http://toki-labs.com:18080"}" local default_edge_addr="${BOOTSTRAP_EDGE_ADDR:-"toki-labs.com:19090"}" - local default_node_token="${BOOTSTRAP_NODE_TOKEN:-"CHANGE_ME_FIELD_TOKEN"}" + local default_node_token="${BOOTSTRAP_NODE_TOKEN:-}" mkdir -p "$bootstrap_dir" cat > "$script" <&2 + echo "[iop-bootstrap] usage: curl -fsSL /bootstrap/node-\$TARGET.sh | bash -s TOKEN" >&2 + exit 2 +fi + echo "[iop-bootstrap] version=\$VERSION target=\$TARGET" echo "[iop-bootstrap] install_dir=\$INSTALL_DIR" mkdir -p "\$INSTALL_DIR" diff --git a/docs/deploy-dev.md b/docs/deploy-dev.md index b0dc8e2..b178b53 100644 --- a/docs/deploy-dev.md +++ b/docs/deploy-dev.md @@ -126,7 +126,7 @@ field 테스트의 1차 기준 환경은 `ssh toki@toki-labs.com`의 code-server | Host port | Container port | Purpose | |---:|---:|---| | `13000-13099` | `3000-3099` | web/dev app preview range | -| `18080` | `18080` | IOP field artifact/bootstrap HTTP | +| `18080` | `18080` | IOP field artifact/bootstrap HTTP 후보. Edge-Node runtime 포트가 아니며, 외부 공개는 테스트 채널로 선택된 경우에만 사용한다. | | `18081` | `8080` | Edge OpenAI-compatible HTTP | | `19080` | `19080` | Portal/Control Plane wire test endpoint | | `19090` | `9090` | Edge-Node TCP transport | @@ -141,50 +141,51 @@ field bootstrap UX는 Jenkins agent 연결처럼 Edge가 command를 제시하고 - 사용자가 실행하는 명령은 한 줄 수준으로 유지하고, 내부에서 다운로드, 실행 권한 부여, config 생성, `iop-node serve`까지 이어진다. - 직접 포트가 아직 적용되지 않았거나 외부망에서 막히면 SSH tunnel 또는 reverse tunnel은 fallback으로만 사용한다. -Apple Silicon Node용 field artifact는 다음처럼 만든다. `BOOTSTRAP_NODE_TOKEN`은 Edge config의 `nodes[].token`과 같아야 한다. +Apple Silicon Node용 field artifact는 다음처럼 만든다. Node token은 artifact에 굽지 않고 사용자 명령의 첫 번째 인자로 전달한다. ```bash VERSION= \ APPS=node \ TARGETS="darwin/arm64" \ -ARTIFACT_BASE_URL="http://toki-labs.com:18080" \ +ARTIFACT_BASE_URL="" \ BOOTSTRAP_EDGE_ADDR="toki-labs.com:19090" \ -BOOTSTRAP_NODE_TOKEN="CHANGE_ME_FIELD_TOKEN" \ DIST_DIR=dist/field \ ./bin/build/field-binaries.sh ``` -산출물 layout과 외부 URL 규칙은 다음을 기준으로 한다. +산출물 layout과 artifact URL 규칙은 다음을 기준으로 한다. ```text dist/field//darwin-arm64/iop-node dist/field//darwin-arm64/SHA256SUMS dist/field//bootstrap/node-darwin-arm64.sh -http://toki-labs.com:18080/darwin-arm64/iop-node -http://toki-labs.com:18080/darwin-arm64/SHA256SUMS -http://toki-labs.com:18080/bootstrap/node-darwin-arm64.sh +/darwin-arm64/iop-node +/darwin-arm64/SHA256SUMS +/bootstrap/node-darwin-arm64.sh ``` 정적 artifact/bootstrap HTTP는 version 디렉터리를 document root로 열어 둔다. ```bash -python3 -m http.server 18080 --bind 0.0.0.0 -d dist/field/ +python3 -m http.server 18080 --bind 127.0.0.1 -d dist/field/ ``` -사용자는 Apple Silicon Mac에서 다음 한 줄을 실행한다. +작업자는 artifact URL을 완성한 뒤 사용자가 token 값 하나만 바꾸는 한 줄 명령을 전달한다. +사용자에게 전달하는 명령에는 `` placeholder를 남기지 않는다. ```bash -curl -fsSL http://toki-labs.com:18080/bootstrap/node-darwin-arm64.sh | bash +curl -fsSL <완성된-bootstrap-url> | bash -s CHANGE_ME_FIELD_TOKEN ``` bootstrap 스크립트는 `~/iop-field`를 만들고, `darwin-arm64/iop-node`와 `SHA256SUMS`를 받아 checksum을 확인한 뒤 `node.yaml`을 생성하고 `iop-node serve --config ./node.yaml`을 실행한다. -실행 시점에 값을 바꾸려면 `IOP_ARTIFACT_BASE_URL`, `IOP_EDGE_ADDR`, `IOP_NODE_TOKEN`, `IOP_HOME`, `IOP_NODE_CONFIG`, `IOP_NODE_METRICS_PORT` 환경변수를 사용할 수 있다. +첫 번째 인자 `CHANGE_ME_FIELD_TOKEN`은 Edge config의 `nodes[].token`과 같은 값이어야 한다. ## Field Bootstrap 작업자 테스트 Runbook 이 절차는 LLM/작업자가 사용자 직접 테스트를 준비하고 실패 지점을 분리할 때 기준으로 삼는다. 사용자에게 전달할 짧은 가이드는 `docs/field-bootstrap-user-test.md`를 사용한다. +다음 작업 재개와 포트 의미 정리는 `docs/field-bootstrap-work-guide.md`를 먼저 확인한다. 토큰과 version 값은 테스트 시점에 맞춰 바꾸고, 기본 `configs/*.yaml`은 수정하지 않는다. ### 1. code-server 포트 확인 @@ -264,9 +265,8 @@ repo root에서 Apple Silicon Node artifact와 bootstrap script를 만든다. VERSION=field-bootstrap-manual \ APPS=node \ TARGETS="darwin/arm64" \ -ARTIFACT_BASE_URL="http://toki-labs.com:18080" \ +ARTIFACT_BASE_URL="" \ BOOTSTRAP_EDGE_ADDR="toki-labs.com:19090" \ -BOOTSTRAP_NODE_TOKEN="CHANGE_ME_FIELD_TOKEN" \ DIST_DIR=dist/field \ ./bin/build/field-binaries.sh ``` @@ -284,7 +284,7 @@ test -x dist/field/field-bootstrap-manual/bootstrap/node-darwin-arm64.sh version 디렉터리를 document root로 열어 둔다. ```bash -python3 -m http.server 18080 --bind 0.0.0.0 -d dist/field/field-bootstrap-manual +python3 -m http.server 18080 --bind 127.0.0.1 -d dist/field/field-bootstrap-manual ``` 다른 터미널에서 URL이 보이는지 확인한다. @@ -294,10 +294,11 @@ curl -fsS http://127.0.0.1:18080/darwin-arm64/SHA256SUMS curl -fsS http://127.0.0.1:18080/bootstrap/node-darwin-arm64.sh | sed -n '1,40p' ``` -외부에서 직접 포트를 사용할 경우 Apple Silicon Mac에서도 같은 URL이 보여야 한다. +artifact HTTP를 외부에서 직접 쓰기로 선택한 경우에만 Apple Silicon Mac에서도 같은 URL이 보여야 한다. +외부 공개 포트를 `19090` 하나로 제한하는 테스트에서는 이 확인을 생략하고, 내부망, front/control-plane, CI artifact, 임시 로컬 HTTP 같은 별도 artifact 채널을 사용한다. ```bash -curl -fsS http://toki-labs.com:18080/darwin-arm64/SHA256SUMS +curl -fsS /darwin-arm64/SHA256SUMS ``` ### 5. Edge serve 시작 @@ -326,20 +327,10 @@ ollama list | grep 'gemma4:26b' ``` 그 다음 one-line bootstrap을 실행한다. +사용자에게 전달할 때는 `<완성된-bootstrap-url>`을 실제 URL로 바꿔 둔다. ```bash -curl -fsSL http://toki-labs.com:18080/bootstrap/node-darwin-arm64.sh | bash -``` - -테스트 중 값을 바꿔야 하면 pipe 오른쪽의 `bash`에 환경변수를 붙인다. - -```bash -curl -fsSL http://toki-labs.com:18080/bootstrap/node-darwin-arm64.sh | \ -IOP_ARTIFACT_BASE_URL="http://toki-labs.com:18080" \ -IOP_EDGE_ADDR="toki-labs.com:19090" \ -IOP_NODE_TOKEN="CHANGE_ME_FIELD_TOKEN" \ -IOP_HOME="$HOME/iop-field" \ -bash +curl -fsSL <완성된-bootstrap-url> | bash -s CHANGE_ME_FIELD_TOKEN ``` 성공하면 Mac에 다음 파일이 생기고, Node process가 foreground로 실행된다. @@ -388,8 +379,8 @@ curl -fsS -N http://127.0.0.1:8080/v1/chat/completions \ 다운로드 실패: ```bash -curl -v http://toki-labs.com:18080/bootstrap/node-darwin-arm64.sh -curl -v http://toki-labs.com:18080/darwin-arm64/iop-node +curl -v /bootstrap/node-darwin-arm64.sh +curl -v /darwin-arm64/iop-node ``` Node가 Edge에 연결하지 못함: @@ -401,7 +392,7 @@ cat ~/iop-field/node.yaml token 불일치: -- Edge config의 `nodes[].token` 값과 bootstrap의 `BOOTSTRAP_NODE_TOKEN` 또는 `IOP_NODE_TOKEN` 값을 맞춘다. +- Edge config의 `nodes[].token` 값과 bootstrap 명령 마지막의 token 인자 값을 맞춘다. Ollama 호출 실패: diff --git a/docs/field-bootstrap-user-test.md b/docs/field-bootstrap-user-test.md index adcdc3b..a4a41db 100644 --- a/docs/field-bootstrap-user-test.md +++ b/docs/field-bootstrap-user-test.md @@ -1,8 +1,9 @@ # Field Bootstrap 직접 테스트 Apple Silicon Mac에서 아래만 실행한다. -``은 그대로 쓰지 말고, 전달받은 실제 테스트 토큰으로 바꾼다. -Edge 설정의 `nodes[].token`과 같은 값이어야 한다. +작업자는 bootstrap URL이 완성된 명령을 전달해야 한다. +사용자는 마지막 token 값 하나만 전달받은 실제 테스트 token으로 바꾼다. +이 token은 Edge 설정의 `nodes[].token`과 같은 값이어야 한다. ## 1. Ollama 준비 @@ -14,14 +15,11 @@ ollama list | grep 'gemma4:26b' ## 2. Node 연결 ```bash -curl -fsSL http://192.168.0.97:18080/bootstrap/node-darwin-arm64.sh | \ -IOP_EDGE_ADDR="192.168.0.97:19090" \ -IOP_NODE_TOKEN="" \ -bash +curl -fsSL <완성된-bootstrap-url> | bash -s ``` -예를 들어 전달받은 토큰이 `abc123`이면 `IOP_NODE_TOKEN="abc123"`로 바꾼다. -전달받은 토큰이 없으면 실행하지 말고 토큰을 먼저 요청한다. +예를 들어 전달받은 토큰이 `abc123`이면 마지막 `` 자리만 `abc123`으로 바꾼다. +전달받은 명령에 `<완성된-bootstrap-url>` 같은 placeholder가 남아 있거나 token이 없으면 실행하지 말고 먼저 요청한다. 성공하면 터미널에 `starting node against toki-labs.com:19090`가 보이고, 프로세스가 계속 실행된다. 종료는 `Ctrl-C`. diff --git a/docs/field-bootstrap-work-guide.md b/docs/field-bootstrap-work-guide.md new file mode 100644 index 0000000..0169db9 --- /dev/null +++ b/docs/field-bootstrap-work-guide.md @@ -0,0 +1,89 @@ +# Field Bootstrap 작업 가이드 + +이 문서는 작업자/LLM이 field bootstrap 테스트를 이어갈 때 읽는 재개 가이드다. +사용자에게 그대로 전달하는 문서는 `docs/field-bootstrap-user-test.md`를 사용하고, 상세 runbook은 `docs/deploy-dev.md`를 확인한다. + +## 핵심 규칙 + +- Edge-Node 런타임 연결에 외부 공개가 필요한 포트는 `19090` 하나다. +- `18080`은 bootstrap shell script, `iop-node` binary, checksum을 내려받는 artifact HTTP 포트다. Edge-Node 런타임 포트가 아니다. +- 외부 공개를 `19090` 하나로 제한할 때는 `toki-labs.com:18080`을 사용자 기본 명령으로 안내하지 않는다. +- bootstrap/artifact는 내부망, front/control-plane, CI artifact, 또는 임시 로컬 HTTP 등 별도 채널로 전달한다. +- 생성되는 `node.yaml`의 `transport.edge_addr`만 외부 접속 주소인 `toki-labs.com:19090`으로 맞춘다. + +## 현재 테스트 값 + +- live version: `field-live-20260527-19ddd9bd38b7` +- node token: `iop-field-20260527-7fd4c675` +- node id: `node-silicon-ollama` +- model: `gemma4:26b` +- edge config 후보: `/tmp/iop-edge-field-bootstrap.yaml` + +위 값은 임시 field 테스트 값이다. 장기 규약으로 고정하지 않는다. + +## 재개 전 확인 + +stale process가 남아 있는지 먼저 본다. + +```bash +ps -ef | rg 'python3 -m http.server 18080|go run ./apps/edge/cmd/edge|/tmp/go-build.*/edge serve|iop-edge serve' +netstat -ltnp 2>/dev/null | rg ':(18080|8080|9090)\b|Proto' || true +``` + +이전 테스트 프로세스가 남아 있으면 정리한 뒤 새 설정으로 띄운다. + +## 권장 테스트 흐름 + +Apple Silicon bootstrap artifact를 만들 때 artifact URL과 edge runtime 주소를 분리한다. + +```bash +VERSION=field-live-20260527-19ddd9bd38b7 \ +APPS=node \ +TARGETS="darwin/arm64" \ +ARTIFACT_BASE_URL="" \ +BOOTSTRAP_EDGE_ADDR="toki-labs.com:19090" \ +DIST_DIR=dist/field \ +./bin/build/field-binaries.sh +``` + +artifact HTTP가 필요하면 내부에서 접근 가능한 경로로만 연다. + +```bash +python3 -m http.server 18080 --bind 127.0.0.1 -d dist/field/field-live-20260527-19ddd9bd38b7 +``` + +Edge는 field config로 실행한다. + +```bash +go run ./apps/edge/cmd/edge serve --config /tmp/iop-edge-field-bootstrap.yaml +``` + +기본 확인: + +```bash +curl -fsS http://127.0.0.1:8080/healthz +curl -fsS http://127.0.0.1:8080/v1/models +nc -vz toki-labs.com 19090 +``` + +사용자에게 전달하는 bootstrap 명령의 URL은 artifact 전달 채널에 맞춰 작업자가 완성한다. +사용자 명령은 token 값 하나만 인자로 받는다. 사용자에게 `` 같은 placeholder를 채우게 하지 않는다. +외부 18080을 열지 않는 흐름에서는 bootstrap script 안의 기본 Edge runtime 주소만 `19090`으로 들어가야 한다. + +```bash +curl -fsSL <완성된-bootstrap-url> | bash -s iop-field-20260527-7fd4c675 +``` + +## 성공 기준 + +- Node host에서 `toki-labs.com:19090`에 연결할 수 있다. +- Edge 로그에 `node registered`가 나온다. +- `/v1/models`가 `gemma4:26b`를 반환한다. +- OpenAI-compatible 호출에서 비어 있지 않은 응답 또는 SSE delta가 나온다. + +## 주의 + +- `curl http://toki-labs.com:18080/... | bash`는 외부 18080 공개를 전제로 하므로 기본 안내로 쓰지 않는다. +- Cline 전용 감지나 provider별 분기는 만들지 않는다. OpenAI-compatible protocol 차원에서 안정화한다. +- 기본 `configs/*.yaml`에 field token이나 임시 host 값을 넣지 않는다. +- 테스트 후에는 임시 edge와 artifact server를 내려둔다.