Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ Mossland 생태계를 탐색하는 지도와 Algora, AO, Bridge의 픽셀 아트
| 화면 | 표시 내용 |
| --- | --- |
| **Algora · Sense & Detect** | 세로 신호 벨트, 9개 작업 단계, 에이전트 클러스터. 벨트는 Algora만이 아니라 **세 서비스 모두**에서 가져온 신호를 합친 큐를 사용합니다. |
| **AO · Debate & Plan** | 캐시된 AO 아이디어와 점수, 토론 주제·발췌문, Ideas / Plans / Projects 총계. 아이디어 버블은 계획 전환 7점, 프로젝트 전환 8점 기준을 시각화합니다. |
| **AO · Debate & Plan** | 캐시된 AO 아이디어와 점수, 최신 토론 3건의 주제와 맥락 발췌문, AO가 직접 보고한 Ideas / Plans / Projects 총계. 아이디어 버블은 계획 전환 7점, 프로젝트 전환 8점 기준을 시각화합니다. |
| **Bridge · Execute & Verify** | L0~L4 작업 흐름, 전문 에이전트, stats의 제안 총계, 에이전트 신뢰도, 최근 결과. 모니터는 전체 제안 목록을 조회하지 않습니다. |

서비스별 역할과 개념적인 거버넌스 루프는 [서비스 개요](docs/mossland-services-overview.md)를 참고하세요. 해당 문서의 서비스 간 데이터 전달 모델은 설계 스케치입니다.

### 데이터 해석 시 알아둘 점

- **푸시 스트림이 아닌 폴링입니다.** 서비스 API는 이전 조회 주기가 끝난 뒤 15초, 상태 조회는 60초, 레지스트리는 10분 후에 갱신합니다. 요청 주기의 제한 시간은 10초입니다.
- **푸시 스트림이 아닌 폴링입니다.** 각 조회는 이전 조회가 끝나고 정해진 시간이 지나면 다시 실행됩니다. `LIVE` 배지와 사이드바 수치의 근거인 각 서비스의 신호·통계는 15초 후에 갱신합니다. 상세 화면의 보조 데이터는 5분 후(AO 아이디어와 프로젝트 총계, Bridge 결과와 에이전트 신뢰도) 또는 10분 후(최신 AO 토론 3건)에 갱신하며, 상세 데이터 조회가 실패하면 1분 후에 다시 시도합니다. 상태 조회는 60초, 레지스트리는 10분 후에 갱신합니다. 신호·통계·상태·레지스트리 요청의 제한 시간은 10초, 상세 데이터 조회는 30초입니다.
- **탭이 숨겨져 있는 동안에는 폴링을 멈춥니다.** 첫 로드는 탭이 백그라운드에서 열렸거나 로드 도중 숨겨지더라도 끝까지 실행합니다. 그 뒤로는 이미 진행 중인 요청은 끝까지 받지만 새 요청은 시작하지 않습니다. 탭이 다시 보이면 그사이 갱신 시점이 지난 조회는 즉시 실행하고, 나머지는 남은 시간만큼 기다립니다. 숨겨져 있는 동안 발행되어 각 서비스의 최신 30건(Algora) 또는 20건(AO, Bridge) 범위를 이미 벗어난 신호는 가져오지 않으므로, "signals ingested this session"은 이 탭이 실제로 관측한 신호만 셉니다.
- **API 응답 여부와 서비스 상태는 다릅니다.** 신호 또는 통계 요청에 성공하면 해당 서비스에 `LIVE` 배지가 붙습니다. 세 서비스 중 하나라도 응답하면 전체 상태는 `LIVE`, 모두 응답하지 않으면 `OFFLINE`, 첫 판단 전에는 `Connecting…`입니다. 생태계 상태 피드는 별도로 상태를 측정합니다.
- **상태는 관측 근거로 판단합니다.** 브라우저가 레지스트리의 `statusUrl`을 직접 조회하며, 직접 측정값이 [city 상태 집계](https://city.moss.land/api/health)보다 우선합니다. HTTP 오류 응답에도 상태가 명시되어 있으면 유지합니다. 비어 있지 않은 문자열 `status`가 없는 5xx 응답(HTML 오류 페이지, 또는 해당 필드가 없는 JSON)은 `down`으로 처리하지만, 네트워크·CORS 실패, 응답을 읽는 도중 끊긴 경우, 유효한 판정이 없는 5xx 이외의 응답만으로는 장애를 단정하지 않습니다. 알 수 없는 상태 문자열도 임의로 바꾸지 않습니다.
- **움직임마다 의미가 다릅니다.** 지도 입자는 새로 수집된 신호에 반응하며 표시 개수에는 제한이 있습니다. 링 스윕은 완료된 상태 조회에 반응합니다. 은하 회전은 장식입니다. 벨트 이동, 단계 전환, Bridge의 제안·증명 애니메이션은 작업 흐름을 설명하며, 실행 추적 기록이나 작업 완료 증거가 아닙니다.
- **최신 조회보다 오래된 스냅샷이 남을 수 있습니다.** 개별 요청이 실패해도 상세 데이터 캐시는 유지되고, 상태 조회가 전부 실패하면 이전 스냅샷을 유지합니다. AO는 캐시된 아이디어를 다시 표시할 수 있습니다. 신뢰도나 성공률이 없을 때, 그리고 서비스가 숫자로 보내지 않은 사이드바 수치는 `—`로 표시하며, 없는 값을 측정된 0으로 해석해서는 안 됩니다. 이 앱은 관측용 뷰어이며 가동 시간이나 실행의 감사 기록이 아닙니다.
- **최신 조회보다 오래된 스냅샷이 남을 수 있습니다.** 개별 요청이 실패해도 상세 데이터 캐시는 유지되고, 상태 조회가 전부 실패하면 이전 스냅샷을 유지합니다. AO는 캐시된 아이디어를 다시 표시할 수 있습니다. 신뢰도나 성공률이 없을 때, 그리고 서비스가 숫자로 보내지 않은 총계는 사이드바, AO 퍼널, Bridge 게이지와 결과 줄에서 `—`로 표시하며, 없는 값을 측정된 0으로 해석해서는 안 됩니다. 이 앱은 관측용 뷰어이며 가동 시간이나 실행의 감사 기록이 아닙니다.

## 로컬 실행

Expand All @@ -63,8 +64,8 @@ Vite가 로컬 주소를 출력하며 기본값은 `http://localhost:5173`입니

| 브라우저 경로 | 개발 환경 기본 업스트림 | 조회 데이터 |
| --- | --- | --- |
| `/algora-api/*` | `http://localhost:3201/api/*` | 신호, 이슈, 통계 |
| `/ao-api/*` | `http://localhost:3001/*` | 신호, 상태, 토론, 아이디어, 계획, 프로젝트 |
| `/algora-api/*` | `http://localhost:3201/api/*` | 신호, 통계 |
| `/ao-api/*` | `http://localhost:3001/*` | 신호, 상태, 토론, 아이디어, 프로젝트 총계 |
| `/bridge-api/*` | `http://localhost:3101/api/*` | 신호, 통계, 결과, 에이전트 신뢰도 |

API 서버는 별도 프로젝트이며 이 저장소에서 실행하지 않습니다. 프런트엔드 API 키나 `.env` 파일은 필요하지 않습니다. 레지스트리와 대체 상태 집계 주소는 [ecosystem-client.ts](src/services/ecosystem-client.ts)에 정의되어 있습니다. 직접 조회하는 상태 엔드포인트는 CORS로 브라우저 접근을 허용해야 합니다. 프로덕션에서는 이 주소들 모두 페이지의 Content-Security-Policy `connect-src` 안에 있어야 합니다([배포](#배포) 참고).
Expand All @@ -77,7 +78,7 @@ npm test
npm run build
```

[GitHub Actions](.github/workflows/ci.yml)는 대상 브랜치와 관계없이 모든 풀 리퀘스트와, 병합이 끝난 `main`에 대해 같은 검사를 실행한 뒤 빌드가 올바른 `dist/health.json`을 생성했는지 확인합니다(`node scripts/check-health-json.mjs`). 풀 리퀘스트 없이 푸시한 브랜치는 자동으로 검사하지 않으므로, 초안 풀 리퀘스트를 열거나 워크플로를 직접 실행하세요. 테스트는 상태 응답 해석, 생태계 피드의 판정·병합·폴링, 서비스 데이터 폴러의 연결 상태·폴링 체인·신호 중복 제거, 사이드바와 지도 툴팁이 마크업에 쓰는 값, 그리고 오리진이 빌드를 서빙하는 방식(없는 파일은 404, 디렉터리 목록 없음)을 검증합니다. 해당 코드를 수정할 때는 `npm run test:watch`를 사용할 수 있습니다.
[GitHub Actions](.github/workflows/ci.yml)는 대상 브랜치와 관계없이 모든 풀 리퀘스트와, 병합이 끝난 `main`에 대해 같은 검사를 실행한 뒤 빌드가 올바른 `dist/health.json`을 생성했는지 확인합니다(`node scripts/check-health-json.mjs`). 풀 리퀘스트 없이 푸시한 브랜치는 자동으로 검사하지 않으므로, 초안 풀 리퀘스트를 열거나 워크플로를 직접 실행하세요. 테스트는 상태 응답 해석, 생태계 피드의 판정·병합·폴링, 서비스 데이터 폴러의 연결 상태·폴링 일정(탭이 숨겨졌을 때의 일시 정지 포함)·신호 중복 제거·상세 화면 총계, 사이드바와 지도 툴팁이 마크업에 쓰는 값과 바뀌지 않은 사이드바 패널을 다시 쓰지 않는 동작, 그리고 오리진이 빌드를 서빙하는 방식(없는 파일은 404, 디렉터리 목록 없음)을 검증합니다. 해당 코드를 수정할 때는 `npm run test:watch`를 사용할 수 있습니다.

```bash
npm run preview # 프로덕션 빌드를 로컬에서 확인
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ The three services are independent. Their stage labels illustrate each service's
| View | Displays |
| --- | --- |
| **Algora · Sense & Detect** | A vertical signal belt, nine workflow stages, and agent clusters. The belt consumes a merged queue of signals fetched from **all three services**, not only Algora. |
| **AO · Debate & Plan** | Cached AO ideas and scores, debate topics/snippets, and Ideas / Plans / Projects totals. Idea bubbles illustrate score thresholds of 7 for a plan and 8 for a project. |
| **AO · Debate & Plan** | Cached AO ideas and scores, topics and context snippets from the three latest debates, and AO's own Ideas / Plans / Projects totals. Idea bubbles illustrate score thresholds of 7 for a plan and 8 for a project. |
| **Bridge · Execute & Verify** | An L0–L4 workflow, specialist agents, proposal totals from stats, agent trust, and recent outcomes. The monitor does not fetch the full proposal collection. |

See [the service overview](docs/mossland-services-overview.md) for responsibilities and the conceptual governance loop. Its cross-service handoff model is a design sketch.

### Reading the data correctly

- **Polling, not a push stream.** Service APIs refresh 15 seconds after the previous cycle finishes. Health sweeps refresh after 60 seconds; the registry after 10 minutes. Requests have a 10-second cycle timeout.
- **Polling, not a push stream.** Each read runs again a fixed time after the previous one finishes. Each service's signals and stats, which the `LIVE` badges and sidebar figures come from, refresh after 15 seconds. The detail views' supporting data refreshes after 5 minutes (AO ideas and project total, Bridge outcomes and agent trust) or 10 minutes (the three latest AO debates), and a detail read that fails is retried after 1 minute. Health sweeps refresh after 60 seconds; the registry after 10 minutes. Signals, stats, health and registry requests time out after 10 seconds; detail reads after 30.
- **Polling pauses while the tab is hidden.** The first load always completes, even in a tab opened in the background or hidden while it runs; after that, a request already under way finishes, but nothing new starts. When the tab is shown again, every read that fell due in the meantime runs at once, and the rest wait out their remaining time. Signals published while the tab was hidden that have already dropped out of each service's newest 30 (Algora) or 20 (AO, Bridge) are never fetched, so "signals ingested this session" counts only what this tab observed.
- **API reachability and health are different.** A service gets a `LIVE` badge when its signals or stats request succeeds. The aggregate is `LIVE` when any of the three responds, `OFFLINE` when none responds, and `Connecting…` before the first verdict. The ecosystem health feed has its own status readings.
- **Health comes from evidence.** The browser reads service `statusUrl` addresses from the registry; direct readings override the [city health aggregate](https://city.moss.land/api/health). A declared status survives an HTTP error response. A 5xx without a non-empty string `status` (an HTML error page, or JSON without the field) means `down`; network/CORS failures, reads cut off mid-response, and non-5xx responses without a usable verdict do not by themselves prove an outage. Unknown status strings stay untranslated.
- **Motion has different meanings.** Map particles are triggered by newly ingested signals and capped for display; a ring sweep follows a completed health refresh. Galaxy rotation is decorative. Belt travel, stage promotion, and Bridge's proposal/proof animation illustrate workflows; they are not execution traces or proof that work completed.
- **Snapshots can be older than the latest poll.** Detail caches survive individual request failures, and a wholly unsuccessful health sweep retains the previous snapshot. AO can replay cached ideas. Missing trust scores, an absent success rate, and sidebar figures a service did not send as a number display `—`; an unavailable value must not be interpreted as a measured zero. This is an observational viewer, not an uptime or execution audit log.
- **Snapshots can be older than the latest poll.** Detail caches survive individual request failures, and a wholly unsuccessful health sweep retains the previous snapshot. AO can replay cached ideas. Missing trust scores, an absent success rate, and totals a service did not send as a number, in the sidebar, the AO funnel and the Bridge gauges and outcome line, display `—`; an unavailable value must not be interpreted as a measured zero. This is an observational viewer, not an uptime or execution audit log.

## Run locally

Expand All @@ -63,8 +64,8 @@ Vite prints the local URL, normally `http://localhost:5173`. The registry and he

| Browser path | Default development upstream | Data read |
| --- | --- | --- |
| `/algora-api/*` | `http://localhost:3201/api/*` | Signals, issues, stats |
| `/ao-api/*` | `http://localhost:3001/*` | Signals, status, debates, ideas, plans, projects |
| `/algora-api/*` | `http://localhost:3201/api/*` | Signals, stats |
| `/ao-api/*` | `http://localhost:3001/*` | Signals, status, debates, ideas, project total |
| `/bridge-api/*` | `http://localhost:3101/api/*` | Signals, stats, outcomes, agent trust |

API servers are separate projects and are not started by this repository. No frontend API key or `.env` file is required. Registry and fallback health URLs are defined in [ecosystem-client.ts](src/services/ecosystem-client.ts); direct health endpoints must permit browser access with CORS. In production all of them must also stay inside the page's Content-Security-Policy `connect-src` (see [Deploy](#deploy)).
Expand All @@ -77,7 +78,7 @@ npm test
npm run build
```

[GitHub Actions](.github/workflows/ci.yml) runs these checks on every pull request, whatever its base branch, and on `main` after each merge, then confirms the build emitted a well-formed `dist/health.json` (`node scripts/check-health-json.mjs`). A branch pushed without an open pull request is not tested automatically; open a draft pull request or run the workflow by hand. Tests cover health-response interpretation; the ecosystem feed's grading, merging and polling; the service-data poller's connection state, polling chain and signal deduplication; the values the sidebar and the map's tooltip write into their markup; and how the origin serves a build (404 for missing files, no directory listing). Use `npm run test:watch` while working on those readers.
[GitHub Actions](.github/workflows/ci.yml) runs these checks on every pull request, whatever its base branch, and on `main` after each merge, then confirms the build emitted a well-formed `dist/health.json` (`node scripts/check-health-json.mjs`). A branch pushed without an open pull request is not tested automatically; open a draft pull request or run the workflow by hand. Tests cover health-response interpretation; the ecosystem feed's grading, merging and polling; the service-data poller's connection state, polling schedules (including the pause while hidden), signal deduplication and detail-view totals; the values the sidebar and the map's tooltip write into their markup, and the sidebar leaving unchanged panels alone; and how the origin serves a build (404 for missing files, no directory listing). Use `npm run test:watch` while working on those readers.

```bash
npm run preview # inspect the production build locally
Expand Down
Loading
Loading