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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- 외부 스케줄러 운영 증거의 시간 권한을 fail-closed로 강화한다. canonical UTC `scheduled_at`/`started_at`이 검증 시점보다 미래인 retained evidence는 `scheduler_timestamp_future`로 거부해 아직 실행되지 않은 hourly run이 운영·인수 준비 증거를 제조하지 못하게 한다.
- strict production KPI provenance를 fail-closed로 강화한다. `collectedAt`은 canonical UTC 시각만 허용하고 미래·존재하지 않는 달력값을 거부하며, `records`는 coercion 없는 양의 safe-integer JSON number로 authenticated log record count와 일치해야 한다. production log는 `O_NOFOLLOW`로 연 verified regular-file descriptor의 identity·size·mode·mtime·ctime을 재검증하면서 동일 verified bytes로 snapshot을 생성해 symlink·pathname replacement·descriptor drift가 KPI authority를 제조하지 못하게 한다.
- 인수 준비성 감사의 buyer/data-room 증거 경계를 실패-폐쇄로 강화한다. `updated_at`은 canonical ISO date 또는 timezone-bearing timestamp만 허용하고 존재하지 않는 달력값·비정규 형식·미래 시각을 거부하며, 명시된 evidence max-age 설정과 매출·고객·LOI·비율 지표는 coercion 없이 유효 도메인을 만족해야 한다. immutable release asset의 `bytes`도 실제 양의 safe-integer JSON number만 인정해 문자열·범위 밖 값이 매각 준비 증거를 제조하지 못하게 한다.
- 루트 `README.md`를 구매자/운영자 표면으로 재작성한다. 제품 정의, 단독 실행, 호스트 호출(HTTP API·`contracts/orchestrator-gateway.json`), 운영 설정을 앞에 두고 naruon·곁(gyeot) 허브-리프 호출을 지원 경로로 문서화한다. CloudAgent/OpenCode 절차, PR 스택, exact-head CI, writer/agent 경계는 `CONTRIBUTING.md`와 `docs/development/contributor-and-agent-procedure.md`로 옮기며 삭제하지 않는다. `test/readme-customer-facing.test.ts`가 README에 봇 매뉴얼 잔여가 남지 않는지 고정한다.
- 루트 `README.md`를 구매자/운영자 표면으로 재작성한다. 제품 정의, 단독 실행, 호스트 호출(`/health`·`/ready`·`/exchange`, `contracts/orchestrator-gateway.json`), GitHub App 권한, 운영자가 설정하는 Worker 변수, naruon·곁(gyeot) 허브-리프 호출을 앞에 둔다. 시간당 상업 루프, 시간당 제품 개발 절차, 매각/판매 가능 프로그램, KPI provenance 수집 레시피, readiness-scan 내부는 README에서 빼고 `docs/internal/README.md`로 안내한다. CloudAgent/OpenCode 절차, PR 스택, exact-head CI, writer/agent 경계는 기존 `CONTRIBUTING.md`와 `docs/development/contributor-and-agent-procedure.md`에 남기며 삭제하지 않는다. `test/readme-customer-facing.test.ts`가 README에 봇 매뉴얼 잔여가 남지 않는지 고정한다.
- repository-owned patch-validator image는 Node.js 24.19.0을 fully static으로 빌드한 `scratch` runtime을 사용하고, `process.versions` 기반 embedded dependency inventory, exact image SHA-256, CycloneDX/Syft/Grype/Trivy evidence, no-network/read-only/non-root smoke를 동일 exact-head receipt에 결합한다.
- 비리뷰 LLM 작업인 `hourly-product-development`를 리뷰와 동일한 `contextual-orchestrator` 게이트웨이 계약(`NOEMA_LLM_API_URL` `/v1`, 모델 별칭 `contextual-orchestrator`, 전용 `NOEMA_LLM_API_KEY`)으로 전환한다. Llama Nemotron → Nemotron Super → DeepSeek 순차 NIM 후보 폴백과 `NVIDIA_NIM_API_KEY` 직접 호출을 제거하고, 공유 `scripts/verify-orchestrator-gateway.mjs`가 `/healthz` 신원과 직접 공급자 호스트를 실패-폐쇄한다. 리뷰어의 `NOEMA_FALLBACK_*` / PydanticAI `FallbackModel` 순차 폴백도 제거해 남은 설정은 실패-폐쇄한다. 동일 계약을 `contracts/orchestrator-gateway.json`으로 공개해 `ContextualWisdomLab/naruon` 판단·결정 에이전트가 1급 소비자로 재사용할 수 있게 한다. naruon 배선은 별도 저장소 PR이다. 상위 공급자 키는 오케스트레이터 KV에 남기며 OIDC 토큰 중개·App 신원·3-runner 샌드박스 경계는 유지한다.
- 검증된 active-orphan 워크플로 하나를 운영자가 호출할 수 있는 `operations:workflow-registry-disable` 경로를 추가한다. 저장소와 워크플로 ID를 `NOEMA_MAINTAINER_TOKEN_PATH` 위임 토큰 파일 읽기 전에 검사하고, 신선한 전체 레지스트리 감사·즉시 live refresh·프로세스 로컬 plan·보호된 main/워크플로 재검증·사후 전체 감사 봉투(`schema_version` 1, `PASS`/`FAIL`, `remaining_failure_codes`, `remaining_active_orphan_ids`)를 통과한 뒤에만 영수증을 유지한다. 성공 종료와 `post_audit_status: FAIL`은 해당 ID만 `disabled_manually`가 되었고 레지스트리는 아직 더럽을 수 있음을 뜻하므로, 운영자는 영수증의 `remaining_active_orphan_ids`로 다음 단일 호출을 이어간다. 배치 비활성화·자가 수리 워크플로·거버넌스 완화는 추가하지 않으며 호출 계약은 doctoring에 기록한다.
Expand Down
163 changes: 34 additions & 129 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ calls it through a published HTTP API and a secret-free LLM gateway contract.
That hub-and-leaf call is the supported MSA path — **따로 또 같이** — not a
reason to merge repositories.

It deploys as a Cloudflare Worker (Free tier) with two jobs:
It deploys as a [Cloudflare Worker](https://developers.cloudflare.com/workers/)
(Free tier) with two jobs:

1. **Token exchange.** GitHub Actions presents an OIDC JWT (audience
`cwl-noema-review`). Noema verifies issuer, audience, organization owner,
and the exact trusted central workflow identity, then returns a
1. **Token exchange.** GitHub Actions presents an
[OIDC](https://docs.github.com/en/actions/reference/security/oidc) JWT
(audience `cwl-noema-review`). Noema verifies issuer, audience, organization
owner, and the exact trusted central workflow identity, then returns a
repository-scoped GitHub App installation token
(`pull_requests: write`, `contents: read`, `checks: read`).
2. **Review.** The default-branch
Expand All @@ -19,11 +21,16 @@ It deploys as a Cloudflare Worker (Free tier) with two jobs:
analysis stays in a separate sandbox; see
[`docs/noema-agent-sandbox-plan.md`](./docs/noema-agent-sandbox-plan.md).

Every Noema LLM job — production review, hourly product development, and
Every Noema LLM job — production review, hourly-product-development, and
host-side judgments — calls `ContextualWisdomLab/contextual-orchestrator`.
Upstream provider keys stay in the orchestrator credential KV. Noema does not
walk a sequential model list or fall back to a direct provider.

OIDC, Worker binding, and Durable Object trust rules are recorded in
[Architecture doctoring](./docs/doctoring/architecture-trust-boundaries.md)
and the [ADR index](./docs/adr/README.md). Do not treat those records as a new
paper list.

## Composition hubs

Leaf products stay independently deployable. Composition hubs call them as
Expand Down Expand Up @@ -87,7 +94,8 @@ Do not reuse `OPENAI_API_KEY` as Noema's gateway token.

## How a host calls it

The public HTTP surface is documented in [`openapi.json`](./openapi.json) and
The public HTTP surface is documented in [`openapi.json`](./openapi.json)
([OpenAPI 3.1](https://spec.openapis.org/oas/v3.1.1.html)) and
[API 명세](./docs/api-spec.md). Every JSON response is
`{ ok: true, data, trace_id }` or
`{ ok: false, error_code, message, details, trace_id }`.
Expand Down Expand Up @@ -131,19 +139,15 @@ The Python reviewer package (`reviewer/`) is the judgement plane. It consumes a
bounded PR manifest and can publish a `ReviewVerdict`. See
[`reviewer/README.md`](./reviewer/README.md).

## Operator-facing review dispatch

`central-review` is default-branch-only. Bind the SHA from a fresh PR read:
After deploy, confirm the HTTP contract:

```bash
gh api repos/ContextualWisdomLab/noema/dispatches -X POST --input - <<'JSON'
{"event_type":"noema-review","client_payload":{"target_repository":"ContextualWisdomLab/example","pr_number":1,"pr_head_sha":"0123456789abcdef0123456789abcdef01234567"}}
JSON
NOEMA_EXCHANGE_URL=https://.../exchange npm run smoke:check
```

Runtime isolation, wait policy, and sandbox controls live in
[`docs/noema-agent-sandbox-plan.md`](./docs/noema-agent-sandbox-plan.md) and
[`docs/development/contributor-and-agent-procedure.md`](./docs/development/contributor-and-agent-procedure.md).
`npm run smoke:check` checks `/health`, `/ready`, and `/exchange` schema,
trace/latency headers, runtime readiness, the unauthenticated 401 Bearer
challenge, and no-store/nosniff headers.

## Required GitHub App permissions

Expand All @@ -166,7 +170,7 @@ Public Worker vars (defaults in `wrangler.toml`):
| `ALLOWED_AUDIENCE` | `cwl-noema-review` | OIDC audience |
| `ALLOWED_REPOSITORY_OWNER` | `ContextualWisdomLab` | Allowed org |
| `ALLOWED_WORKFLOW_REPOSITORY` | `ContextualWisdomLab/.github` | Trusted workflow repo |
| `ALLOWED_WORKFLOW_REF_PREFIX` | `/noema-review.yml@refs/heads/main` | Exact trusted workflow ref (name kept; matching is exact, not prefix) |
| `ALLOWED_WORKFLOW_REF_PREFIX` | `ContextualWisdomLab/.github/.github/workflows/noema-review.yml@refs/heads/main` | Exact trusted workflow ref (name kept; matching is exact, not prefix) |
| `GITHUB_API_BASE` | `https://api.github.com` | GitHub Cloud API origin |
| `NOEMA_RATE_LIMIT_PER_MINUTE` | `60` | `/exchange` fixed-window budget |
| `NOEMA_OIDC_JWKS_CACHE_TTL_SECONDS` | `300` | OIDC JWKS cache |
Expand All @@ -176,123 +180,24 @@ Public Worker vars (defaults in `wrangler.toml`):
across Worker isolates, then keeps the isolate-local limiter as defense in
depth. Missing or malformed distributed decisions fail closed; see
[Distributed rate limiting](./docs/distributed-rate-limiting.md).
OIDC `jti` values are consumed once by a Durable Object replay guard.
OIDC `jti` values are consumed once by a Durable Object replay guard; see
[OIDC replay protection](./docs/oidc-replay-protection.md).

## 판매/운영 패키지
## Operator documentation

- [API 명세](./docs/api-spec.md)
- [안정성 계약](./docs/api-stability-contract.md)
- [Orchestrator gateway consumer contract](./docs/orchestrator-gateway-consumer-contract.md)
- [온보딩 가이드](./docs/onboarding.md)
- [운영 Runbook](./docs/runbook.md)
- [Distributed Rate Limiting](./docs/distributed-rate-limiting.md)
- [Runtime readiness](./docs/runtime-readiness.md)
- [Hourly Commercial-Readiness Loop](./docs/hourly-commercial-readiness-loop.md)
- [Hourly Orchestrator Product Development](./docs/operations/hourly-product-development.md)
- [SLA/지원 정책](./docs/sla-and-support.md)
- [가격 초안](./docs/pricing-draft.md)
- [관측성 KPI](./docs/observability-kpi.md)
- [API 명세](./docs/api-spec.md)
- [안정성 계약](./docs/api-stability-contract.md)
- [OpenAPI](./openapi.json)
- [보안/위협 모델](./docs/threat-model.md)
- [이용약관 초안](./docs/terms-draft.md)
- [배포 가이드](./docs/deployment-guide.md)
- [보안 검증 체크리스트](./docs/security-validation-checklist.md)
- [파일럿 온보딩 체크리스트](./docs/pilot-readiness-checklist.md)
- [출시 준비 감사서](./docs/release-readiness-audit.md)
- [Buyer Pitch Deck Outline](./docs/buyer-pitch-deck-outline.md)
- [판매 가능 Goal 등록서](./docs/saleable-program-goal-registry.md)
- [판매 가능 프로그램 Goal](./docs/saleable-program-readiness.md)
- [목표 완료 감사서](./docs/goal-completion-audit.md)
- [20억 매각 가능성 Goal 등록서](./docs/acquisition-readiness-2b.md)
- [Buyer Due Diligence Index](./docs/buyer-due-diligence-index.md)
- [Transfer Readiness Plan](./docs/transfer-readiness-plan.md)
- [Library Boundary Decision](./docs/library-boundary-decision.md)
- [Contributing](./CONTRIBUTING.md)

## KPI 계산

```bash
npm run kpi:compute
npm run kpi:check
npm run kpi:alerts
npm run kpi:verify
NOEMA_KPI_TAIL_COMMAND='timeout 30s wrangler tail noema --env production --format json' \
NOEMA_KPI_LOG_PATH=exchange-30d.ndjson \
NOEMA_KPI_SOURCE_KIND=production \
NOEMA_KPI_SOURCE_ID=cloudflare-logpush:noema-production \
npm run kpi:collect
# 또는 Logpush/아카이브 URL 직접 사용
NOEMA_KPI_LOG_URL=https://.../exchange-30d.ndjson \
NOEMA_KPI_LOG_PATH=exchange-30d.ndjson \
NOEMA_KPI_SOURCE_KIND=production \
NOEMA_KPI_SOURCE_ID=cloudflare-logpush:noema-production \
npm run kpi:collect
NOEMA_KPI_REQUIRE_WINDOW_DAYS=30 npm run kpi:verify:strict
```

`exchange-30d.ndjson`은 운영 30일 로그 집계용 파일입니다.
`kpi:collect`는 `exchange-30d.ndjson.provenance.json`을 함께 생성하며, strict KPI 게이트는 `sourceKind=production`, `sourceId`, `records`, `collectedAt`이 있는 provenance 파일을 요구합니다.
`wrangler tail`은 실시간 수집이므로, 30일 집계는 Logpush/외부 파이프라인 또는 임시 저장본을 `exchange-30d.ndjson`로 구성해야 합니다.

## 배포 전 스모크 체크

```bash
NOEMA_EXCHANGE_URL=https://.../exchange npm run smoke:check
```

`npm run smoke:check`는 `/health`, `/ready`, `/exchange`의 스키마, 추적/지연 헤더, runtime readiness, 401 Bearer challenge, no-store/nosniff 보안 헤더를 확인하고 실패 내역을 JSON으로 출력하며,
배포에서 `NOEMA_SMOKE_EVIDENCE_PATH`를 지정하면 `noema-smoke-evidence.json` 형태로 증빙을 저장할 수 있습니다.

CI/CD의 `cd` 워크플로우는 동일 스크립트를 실행해 `/health`/`/ready`/`/exchange` 계약을 검증합니다.

운영 증빙 수집 전에는 다음 preflight로 production URL과 KPI 로그 수집 입력이 준비됐는지 확인합니다.

```bash
NOEMA_EXCHANGE_URL=https://.../exchange \
NOEMA_KPI_SOURCE_KIND=production \
NOEMA_KPI_SOURCE_ID=cloudflare-logpush:noema-production \
NOEMA_KPI_LOG_URL=https://.../exchange-30d.ndjson \
npm run production:preflight
```

`production:preflight`는 증빙을 생성하지 않으며, smoke/KPI evidence 수집 전 누락된 입력을 fail-fast로 알려줍니다.

## 판매 가능성 자동 감사

```bash
npm run readiness:audit
NOEMA_EXCHANGE_URL=https://.../exchange npm run readiness:audit
```

- `npm run readiness:audit`는 기술게이트, 보안/테스트, KPI strict(가능한 경우), smoke 증빙(환경변수 지정 시), 파일럿 완료 증빙까지 한 번에 검사합니다.
- `docs/security-validation-checklist.md`의 미체크 항목은 readiness audit 실패로 처리됩니다.
- 결과는 `artifacts/saleable-readiness/<YYYYMMDD>/goal-audit.json`에 저장됩니다.
- 파일럿 완료 증빙은 production HTTPS `NOEMA URL`, `증빙 출처: production`, `계약/매출 증빙 경로`가 있어야 인정됩니다.
- `readiness-scan` 워크플로우(`.github/workflows/readiness-scan.yml`)는 UTC 01:00 기준으로 정기 `readiness:audit`를 실행해 증빙을 `saleable-readiness-audit` 아티팩트로 보존합니다.
- 정기 `schedule` 실행은 누락된 production evidence를 `NOT_READY` status, warning, artifact로 남기는 감시 작업이며, `workflow_dispatch`와 로컬 `npm run readiness:audit`는 동일한 누락을 실패로 유지합니다.

## 20억 매각 가능성 감사

```bash
npm run acquisition:manifest
npm run acquisition:audit
```

- `npm run acquisition:manifest`는 buyer data room 파일, 명령, 외부 Figma 자산, 최종 evidence 경로를 `artifacts/acquisition-readiness/<YYYYMMDD>/data-room-manifest.json`으로 해시/색인합니다.
- manifest의 최종 evidence 항목은 파일 존재를 색인하며, 증빙 내용의 유효성은 `validatedBy`에 적힌 `npm run acquisition:audit` 통과로 판정합니다.
- `npm run acquisition:audit`는 `KRW 2,000,000,000` 매각 협상 기준의 실사 패키지를 검사합니다.
- `npm run security:evidence`는 보안 체크리스트와 reviewed security evidence만 단독 검증합니다.
- 기본 evidence path는 `artifacts/acquisition/revenue-evidence.json`, `artifacts/acquisition/transfer-evidence.json`, `docs/pilot-readiness-log.md`, 그리고 가장 최신 `artifacts/saleable-readiness/<YYYYMMDD>/goal-audit.json`입니다.
- `NOEMA_PILOT_LOG_PATH`로 별도 production 파일럿 로그를 지정할 수 있습니다.
- ARR/LOI/weighted pipeline, production 유료 파일럿, IP/license/권한 이전성, saleable readiness가 모두 증빙되지 않으면 실패합니다.
- revenue/transfer evidence는 `owner`, `source_documents`, 기본 45일 이내 `updated_at` 메타데이터가 없으면 실패합니다.
- `acquisition-readiness-audit` 워크플로우(`.github/workflows/acquisition-readiness-scan.yml`)는 매일 `acquisition:manifest`와 `acquisition:audit`를 실행하고 evidence artifact를 보존합니다.
- 정기 `schedule` 실행은 production/acquisition evidence 누락을 `NOT_READY` status, warning, artifact로 남기는 감시 작업이며, `workflow_dispatch`와 로컬 `npm run acquisition:audit`는 동일한 누락을 실패로 유지합니다.
- submodule은 현재 사용하지 않으며, `docs/library-boundary-decision.md`의 split trigger가 충족될 때 npm workspace package 분리를 검토합니다.

## 릴리스 검증

```bash
npm run release:verify
```
- [SLA/지원 정책](./docs/sla-and-support.md)
- [Runtime readiness](./docs/runtime-readiness.md)
- [Distributed Rate Limiting](./docs/distributed-rate-limiting.md)
- [Orchestrator gateway consumer contract](./docs/orchestrator-gateway-consumer-contract.md)

운영/프로덕션 배포 경로는 `.github/workflows/cd.yml`에서 `npm run release:verify:strict`를 사용하며, 실패 시 KPI 증빙(`noema-kpi-evidence.json`)과 provenance(`exchange-30d.ndjson.provenance.json`)는 워크플로우 Artifact로 저장됩니다.
Maintainers and coding agents: start at
[`docs/internal/README.md`](./docs/internal/README.md)
(contributor and agent procedure:
[`docs/development/contributor-and-agent-procedure.md`](./docs/development/contributor-and-agent-procedure.md)).
Loading
Loading