haechi 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -4,17 +4,19 @@
4
4
  [![CI](https://github.com/raeseoklee/haechi/actions/workflows/ci.yml/badge.svg)](https://github.com/raeseoklee/haechi/actions/workflows/ci.yml)
5
5
  [![license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
6
6
  [![node](https://img.shields.io/node/v/haechi)](https://nodejs.org)
7
- [![status](https://img.shields.io/badge/status-developer%20preview-orange)](docs/current/risk-register-release-gate.md)
7
+ [![status](https://img.shields.io/badge/status-stable%201.0-brightgreen)](docs/current/api-stability.md)
8
8
 
9
9
  [English](README.md) | **한국어**
10
10
 
11
- Haechi는 LLM, MCP, vLLM, Ollama, 그리고 에이전트 payload가 모델, 도구, 로그, 또는 proxy에 도달하기 전에 보호하기 위한 자체 호스팅 AI 컨텍스트 집행 레이어의 실험적 개발자 프리뷰이다.
11
+ Haechi는 LLM, MCP, vLLM, Ollama, 그리고 에이전트 payload가 모델, 도구, 로그, 또는 proxy에 도달하기 전에 보호하기 위한 자체 호스팅 AI 컨텍스트 집행 레이어이다.
12
12
 
13
13
  이름은 분별력과 보호를 상징하는 한국의 수호 신수 해치에서 유래했다.
14
14
 
15
- 이 저장소는 로컬 개발, 보안 설계 검토, 자체 호스팅 통합 실험을 위한 것이다. 운영 환경에 바로 사용할 수 있는 상태가 아니며, 컴플라이언스를 보장하지 않는다.
15
+ 이 저장소는 로컬 개발, 보안 설계 검토, 자체 호스팅 통합 실험을 위한 것이다. 컴플라이언스를 보장하지 않는다.
16
16
 
17
- 현재 개발자 프리뷰 범위는 로컬 도입에 초점을 맞추고 있다:
17
+ **1.0.0이 stable 릴리스다.** 1.0부터 public API는 strict semver 하의 frozen 계약이다: `package.json` `exports` 표면, CLI의 기계가 읽는 동작, audit event schema, config key shape이 모두 major 버전 계약의 일부이며, 문서화된 deprecation 정책과 단 하나의 in-minor 보안 예외가 함께한다. [`docs/current/api-stability.md`](docs/current/api-stability.md) 참고. 네 개의 `haechi-*` 위성은 pre-1.0으로 유지되며 core와 독립적으로 버저닝한다.
18
+
19
+ 현재 범위는 로컬 도입에 초점을 맞추고 있다:
18
20
 
19
21
  - `haechi init`: 로컬 키, 샘플 설정, audit 경로를 생성한다
20
22
  - `haechi protect`: OpenAI 호환 JSON payload를 검사하고 보호한다
@@ -167,12 +169,12 @@ haechi auth revoke <id>
167
169
  - **Rate limit**: identity별 분당 요청 수 → `429` (인메모리, 프로세스별).
168
170
  - Audit 이벤트는 **PII-safe** `identity`(keyed-HMAC subject/issuer, 원시 값 아님)와 resolve된 `profile`을 포함하며, `auth_denied` / `model_not_allowed` / `rate_limited` 결정에는 credentials가 포함되지 않는다. `/__haechi/health`는 인증 없이 접근 가능하다.
169
171
 
170
- JWT/JWKS 인증과 KMS 기반 key custody는 `haechi-*` 위성 패키지로 제공되며, 각각 core와 독립적으로 버저닝·발행된다:
172
+ JWT/JWKS 인증과 KMS 기반 key custody는 `haechi-*` 위성 패키지로 제공되며, 각각 core와 독립적으로 버저닝·발행된다. 위성들은 pre-1.0으로 유지되며 `haechi` peer 범위를 `>=0.8.0 <2.0.0`으로 선언한다(상한이 core major를 추적하므로 core 1.0.0이 위성 설치를 깨뜨리지 않는다):
171
173
 
172
- - [`haechi-auth-jwt`](satellites/auth-jwt/) (0.8) — 헤드리스 JWKS bearer 검증; 0.2.0은 재사용 가능한 JWS 검증기(`createJwtVerifier`)를 추가 export한다.
173
- - [`haechi-crypto-kms`](satellites/crypto-kms/) (0.8) — 실제 KMS 클라이언트 기반 envelope 암호화; 0.2.0은 AWS에 더해 GCP(`./gcp`), Azure(`./azure`), HashiCorp Vault Transit(`./vault`, `node:` 전용) 백엔드를 추가한다.
174
- - [`haechi-dashboard`](satellites/dashboard/) (0.9, 신규) — audit 로그와 hash chain 상태에 대한 zero-dependency 읽기 전용 audit 뷰어(`node:http`).
175
- - [`haechi-auth-oidc`](satellites/auth-oidc/) (0.9, 신규) — 대시보드의 사람 로그인을 제공하는 대화형 OIDC 세션 브로커(authorization-code + PKCE).
174
+ - [`haechi-auth-jwt`](satellites/auth-jwt/) (0.2.1) — 헤드리스 JWKS bearer 검증; 재사용 가능한 JWS 검증기(`createJwtVerifier`)를 추가 export한다.
175
+ - [`haechi-crypto-kms`](satellites/crypto-kms/) (0.2.1) — 실제 KMS 클라이언트 기반 envelope 암호화; AWS에 더해 GCP(`./gcp`), Azure(`./azure`), HashiCorp Vault Transit(`./vault`, `node:` 전용) 백엔드.
176
+ - [`haechi-dashboard`](satellites/dashboard/) (0.1.2) — audit 로그와 hash chain 상태에 대한 zero-dependency 읽기 전용 audit 뷰어(`node:http`).
177
+ - [`haechi-auth-oidc`](satellites/auth-oidc/) (0.1.2) — 대시보드의 사람 로그인을 제공하는 대화형 OIDC 세션 브로커(authorization-code + PKCE).
176
178
 
177
179
  위성들은 기본 `node:` 전용이며(무거운 SDK는 optional peer) core를 zero-dependency로 유지한다.
178
180
 
@@ -253,7 +255,8 @@ Haechi는 로컬 정책 부트스트래핑을 위한 기본 지역별 Privacy Pr
253
255
  - Audit tail truncation: `audit.anchor.mode: file`을 설정하면(추가 전용/별도 미디어에서) `haechi audit-verify --anchor`가 마지막 anchor 이후 꼬리 레코드 삭제를 탐지한다. 동일한 쓰기 가능 파일시스템에서는 공격자가 두 파일을 함께 잘라낼 수 있다.
254
256
  - Key custody: `keys.provider: external`은 주입된 `cryptoProvider`를 허용한다; `assertCryptoProviderConformance`로 adapter를 검증한다. envelope 암호화 KMS adapter는 `haechi-crypto-kms` satellite(`satellites/crypto-kms/`)가 제공한다.
255
257
  - Release integrity: 배포된 tarball에는 npm provenance attestation이 포함되며, GitHub release asset에는 sigstore attestation과 `SHA256SUMS`가 추가된다(`gh attestation verify`와 `node scripts/release-checksums.mjs --check`로 검증한다).
256
- - 패키지는 개발자 프리뷰이다. 인터넷에 노출된 운영 LLM 게이트웨이로 사용하지 않는다.
258
+ - 1.0 authProvider 플러그인 샌드박스는 서명된 플러그인을 `worker_threads` worker에서 실행한다. 이는 메모리/크래시 격리와 데이터 최소화(credential 슬라이스만 넘어가고, host가 keyed-HMAC identity를 만든다)이며 capability 샌드박스가 **아니다**: 악의적인 *서명된* 플러그인은 여전히 `fs`/`net`을 사용해 받은 credential을 유출할 수 있다. load-bearing 통제는 trust gate(Ed25519 서명 + 운영자 allowlist + 버전 pin/floor + revocation)다. 기본 배선은 dependency injection(`createRuntime(config, providers)`)으로 유지되며, 진정한 capability 강제(child-process + Node permission model)는 1.x 목표다.
259
+ - 자체 네트워크 통제와 인증을 앞에 두지 않고 Haechi를 인터넷에 노출된 운영 LLM 게이트웨이로 사용하지 않는다.
257
260
 
258
261
  ## 현재 범위
259
262
 
@@ -278,3 +281,5 @@ Haechi는 로컬 정책 부트스트래핑을 위한 기본 지역별 Privacy Pr
278
281
  0.8.0은 `haechi-*` 에코시스템을 세운다: npm workspaces 모노레포(core는 unscoped `haechi` 유지, zero runtime dependency, 패킹 매니페스트 CI 게이트로 강제) + 첫 두 위성 — [`haechi-crypto-kms`](satellites/crypto-kms/)(실제 AWS KMS 클라이언트 기반 envelope 암호화; AWS SDK는 optional peer)와 [`haechi-auth-jwt`](satellites/auth-jwt/)(헤드리스 JWKS bearer 검증, `node:` 전용). 각각 자체 provenance + sigstore attest 워크플로로 독립 발행한다. `docs/current/release-0.8-implementation-scope.md` 참고.
279
282
 
280
283
  0.9.0은 관측성(observability) + 대화형 인증 테마이다: 두 개의 새 위성 — [`haechi-dashboard`](satellites/dashboard/)(audit 로그와 hash chain 상태에 대한 zero-dependency 읽기 전용 `node:http` audit 뷰어; anti-DNS-rebinding Host allowlist, 엄격한 CSP/Trusted Types, fail-closed loopback/remote-bind 가드 포함)와 [`haechi-auth-oidc`](satellites/auth-oidc/)(대시보드의 사람 로그인을 제공하는 대화형 OIDC 세션 브로커 — authorization-code + PKCE + 서버측 세션). 기존 위성도 additive minor를 발행한다: `haechi-auth-jwt@0.2.0`은 재사용 가능한 JWS 검증기(`createJwtVerifier`)를 export하고, `haechi-crypto-kms@0.2.0`은 GCP/Azure/Vault 백엔드를 추가한다. core는 `0.9.0`으로 bump되며, 추가적인 `FORBIDDEN_KEYS` audit 새니타이즈 강화(현재 이벤트 출력은 바뀌지 않는 심층 방어)만 포함한다. `docs/current/release-0.9-implementation-scope.md` 참고.
284
+
285
+ 1.0.0은 **첫 stable 릴리스**다. strict semver 하의 frozen API 계약을 선언한다: `package.json` `exports` 표면, CLI의 기계가 읽는 동작, audit event schema(중첩 sub-schema와 `schemaVersion` 포함), config key shape이 모두 major 버전 계약의 일부이며, `tests/api-contract.test.mjs`가 이를 가드하고 문서화된 deprecation 정책(`HAECHI_DEPRECATION_*` 런타임 경고, 제거는 다음 major에서만)과 공개된 취약점에 대한 단 하나의 in-minor 보안 예외가 이를 규율한다([`docs/current/api-stability.md`](docs/current/api-stability.md) 참고). 1.0은 또한 dynamic-loading 금지를 **좁게** 해제한다 — `authProvider` 플러그인에 한해: Ed25519 서명(trust-anchor 전용 키 해석, entry-hash 바인딩, 버전 pin/floor, revocation, 서명 윈도우를 갖춘 비대칭 `node:crypto` 검증), capability-gated, `worker_threads` 격리, 완전 감사되는 플러그인 샌드박스. dependency injection(`createRuntime(config, providers)`)이 기본으로 유지된다. **정직한 잔존 위험:** worker는 메모리/크래시 격리와 데이터 최소화이며 capability 샌드박스가 아니다 — 악의적인 *서명된* 플러그인은 여전히 `fs`/`net`을 사용해 받은 credential 슬라이스를 유출할 수 있으므로 load-bearing 통제는 trust gate다; 진정한 capability 강제(child-process + Node permission model)는 1.x 목표다. 네 개의 `haechi-*` 위성(`haechi-auth-jwt@0.2.1`, `haechi-crypto-kms@0.2.1`, `haechi-dashboard@0.1.2`, `haechi-auth-oidc@0.1.2`)은 pre-1.0으로 유지되고 독립적으로 버저닝하며, `haechi` peer 범위를 `>=0.8.0 <2.0.0`으로 넓혀 core 1.0.0이 그 설치를 깨뜨리지 않게 한다. `docs/current/release-1.0-implementation-scope.md` 참고.
package/README.md CHANGED
@@ -4,17 +4,19 @@
4
4
  [![CI](https://github.com/raeseoklee/haechi/actions/workflows/ci.yml/badge.svg)](https://github.com/raeseoklee/haechi/actions/workflows/ci.yml)
5
5
  [![license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
6
6
  [![node](https://img.shields.io/node/v/haechi)](https://nodejs.org)
7
- [![status](https://img.shields.io/badge/status-developer%20preview-orange)](docs/current/risk-register-release-gate.md)
7
+ [![status](https://img.shields.io/badge/status-stable%201.0-brightgreen)](docs/current/api-stability.md)
8
8
 
9
9
  **English** | [한국어](README.ko.md)
10
10
 
11
- Haechi is an experimental developer preview of a self-hosted AI context enforcement layer for protecting LLM, MCP, vLLM, Ollama, and agent payloads before they reach models, tools, logs, or proxies.
11
+ Haechi is a self-hosted AI context enforcement layer for protecting LLM, MCP, vLLM, Ollama, and agent payloads before they reach models, tools, logs, or proxies.
12
12
 
13
13
  The name comes from Haechi, a Korean guardian figure associated with discernment and protection.
14
14
 
15
- This repository is intended for local development, security design review, and self-hosted integration experiments. It is not production-ready and is not a compliance guarantee.
15
+ This repository is intended for local development, security design review, and self-hosted integration experiments. It is not a compliance guarantee.
16
16
 
17
- The current developer-preview scope focuses on local adoption:
17
+ **1.0.0 is the first stable release.** From 1.0 the public API is a frozen contract under strict semver: the `package.json` `exports` surface, the CLI's machine-readable behavior, the audit event schema, and the config key shape are all part of the major-versioned contract, with a documented deprecation policy and a one in-minor security exception. See [`docs/current/api-stability.md`](docs/current/api-stability.md). The four `haechi-*` satellites stay pre-1.0 and version independently of core.
18
+
19
+ The current scope focuses on local adoption:
18
20
 
19
21
  - `haechi init`: create a local key, sample config, and audit path
20
22
  - `haechi protect`: inspect and protect an OpenAI-compatible JSON payload
@@ -167,12 +169,12 @@ haechi auth revoke <id>
167
169
  - **Rate limit**: per-identity requests-per-minute → `429` (in-memory, per-process).
168
170
  - Audit events carry the **PII-safe** `identity` (keyed-HMAC subject/issuer, never raw values) and the resolved `profile`; `auth_denied` / `model_not_allowed` / `rate_limited` decisions never include credentials. `/__haechi/health` stays unauthenticated.
169
171
 
170
- JWT/JWKS auth and KMS-backed key custody ship as `haechi-*` satellite packages, each versioned and published independently of core:
172
+ JWT/JWKS auth and KMS-backed key custody ship as `haechi-*` satellite packages, each versioned and published independently of core. They remain pre-1.0 and declare a `haechi` peer range of `>=0.8.0 <2.0.0` (the upper bound tracks the core major, so core 1.0.0 does not break satellite installs):
171
173
 
172
- - [`haechi-auth-jwt`](satellites/auth-jwt/) (0.8) — headless JWKS bearer verification; 0.2.0 additively exports a reusable JWS verifier (`createJwtVerifier`).
173
- - [`haechi-crypto-kms`](satellites/crypto-kms/) (0.8) — envelope encryption with a real KMS client; 0.2.0 adds GCP (`./gcp`), Azure (`./azure`), and HashiCorp Vault Transit (`./vault`, `node:`-only) backends alongside AWS.
174
- - [`haechi-dashboard`](satellites/dashboard/) (0.9, new) — a zero-dependency, read-only audit viewer (`node:http`) over the audit log and its hash-chain status.
175
- - [`haechi-auth-oidc`](satellites/auth-oidc/) (0.9, new) — an interactive OIDC session broker (authorization-code + PKCE) that provides the dashboard's human login.
174
+ - [`haechi-auth-jwt`](satellites/auth-jwt/) (0.2.1) — headless JWKS bearer verification; additively exports a reusable JWS verifier (`createJwtVerifier`).
175
+ - [`haechi-crypto-kms`](satellites/crypto-kms/) (0.2.1) — envelope encryption with a real KMS client; AWS plus GCP (`./gcp`), Azure (`./azure`), and HashiCorp Vault Transit (`./vault`, `node:`-only) backends.
176
+ - [`haechi-dashboard`](satellites/dashboard/) (0.1.2) — a zero-dependency, read-only audit viewer (`node:http`) over the audit log and its hash-chain status.
177
+ - [`haechi-auth-oidc`](satellites/auth-oidc/) (0.1.2) — an interactive OIDC session broker (authorization-code + PKCE) that provides the dashboard's human login.
176
178
 
177
179
  The satellites are `node:`-only by default (heavy SDKs are optional peers) and keep core zero-dependency.
178
180
 
@@ -253,7 +255,8 @@ Set `privacy.profile` in `haechi.config.json` to apply the profile's default act
253
255
  - Audit tail truncation: set `audit.anchor.mode: file` (on append-only/separate media) so `haechi audit-verify --anchor` detects deletion of trailing records back to the last anchor. On the same writable filesystem an attacker can truncate both files together.
254
256
  - Key custody: `keys.provider: external` accepts an injected `cryptoProvider`; validate adapters with `assertCryptoProviderConformance`. The `haechi-crypto-kms` satellite (`satellites/crypto-kms/`) provides an envelope-encryption KMS adapter.
255
257
  - Release integrity: published tarballs carry an npm provenance attestation; GitHub release assets add a sigstore attestation and `SHA256SUMS` (verify with `gh attestation verify` and `node scripts/release-checksums.mjs --check`).
256
- - The package is a developer preview. Do not expose it as an internet-facing production LLM gateway.
258
+ - The 1.0 authProvider plugin sandbox runs a signed plugin in a `worker_threads` worker. This is memory/crash isolation and data-minimization (only the credential slice crosses; the host builds the keyed-HMAC identity), **not** a capability sandbox: a malicious *signed* plugin can still use `fs`/`net` and exfiltrate the credential it receives. The load-bearing control is the trust gate (Ed25519 signature + operator allowlist + version pin/floor + revocation). Default wiring stays dependency injection (`createRuntime(config, providers)`); true capability enforcement (child-process + Node permission model) is a 1.x target.
259
+ - Do not expose Haechi as an internet-facing production LLM gateway without your own network controls and authentication in front.
257
260
 
258
261
  ## Current Scope
259
262
 
@@ -278,3 +281,5 @@ Set `privacy.profile` in `haechi.config.json` to apply the profile's default act
278
281
  0.8.0 stands up the `haechi-*` ecosystem: an npm workspaces monorepo (core stays the unscoped `haechi`, zero runtime dependency, gated by a packed-manifest CI check) plus the first two satellites — [`haechi-crypto-kms`](satellites/crypto-kms/) (envelope encryption with a real AWS KMS client; the AWS SDK is an optional peer) and [`haechi-auth-jwt`](satellites/auth-jwt/) (headless JWKS bearer verification, `node:`-only). Each publishes independently with its own provenance + sigstore-attested workflow. See `docs/current/release-0.8-implementation-scope.md`.
279
282
 
280
283
  0.9.0 is the observability + interactive-auth theme: two new satellites — [`haechi-dashboard`](satellites/dashboard/) (a zero-dependency, read-only `node:http` audit viewer over the audit log and its hash-chain status, with an anti-DNS-rebinding Host allowlist, strict CSP/Trusted Types, and fail-closed loopback/remote-bind guards) and [`haechi-auth-oidc`](satellites/auth-oidc/) (an interactive OIDC session broker — authorization-code + PKCE + server-side sessions — that provides the dashboard's human login). Existing satellites also ship additive minors: `haechi-auth-jwt@0.2.0` exports a reusable JWS verifier (`createJwtVerifier`) and `haechi-crypto-kms@0.2.0` adds GCP/Azure/Vault backends. Core bumps to `0.9.0`, carrying only an additive `FORBIDDEN_KEYS` audit-sanitization hardening — defense-in-depth that changes no current event output. See `docs/current/release-0.9-implementation-scope.md`.
284
+
285
+ 1.0.0 is the **first stable release**. It declares a frozen API contract under strict semver: the `package.json` `exports` surface, the CLI's machine-readable behavior, the audit event schema (including its nested sub-schemas and `schemaVersion`), and the config key shape are all part of the major-versioned contract, guarded by `tests/api-contract.test.mjs` and governed by a documented deprecation policy (`HAECHI_DEPRECATION_*` runtime warnings, removal only at the next major) with a single in-minor security exception for disclosed vulnerabilities (see [`docs/current/api-stability.md`](docs/current/api-stability.md)). 1.0 also lifts the dynamic-loading ban **narrowly**, for `authProvider` plugins only: an Ed25519-signed (asymmetric `node:crypto` verification with trust-anchor-only key resolution, entry-hash binding, version pin/floor, revocation, and a signing window), capability-gated, `worker_threads`-isolated, fully audited plugin sandbox. Dependency injection (`createRuntime(config, providers)`) stays the default. **Honest residual:** the worker is memory/crash isolation and data-minimization, not a capability sandbox — a malicious *signed* plugin can still use `fs`/`net` and exfiltrate the credential slice it receives, so the load-bearing control is the trust gate; true capability enforcement (child-process + Node permission model) is a 1.x target. The four `haechi-*` satellites (`haechi-auth-jwt@0.2.1`, `haechi-crypto-kms@0.2.1`, `haechi-dashboard@0.1.2`, `haechi-auth-oidc@0.1.2`) stay pre-1.0, version independently, and widen their `haechi` peer range to `>=0.8.0 <2.0.0` so core 1.0.0 does not break their installs. See `docs/current/release-1.0-implementation-scope.md`.
@@ -1,61 +1,107 @@
1
1
  # Haechi API Stability Policy
2
2
 
3
- - 문서 상태: Draft 0.1
4
- - 작성일: 2026-06-10
5
- - 기준 버전: 0.7.0
3
+ - 문서 상태: 발효 중 (1.0 계약 — API freeze)
4
+ - 작성일: 2026-06-11
5
+ - 적용 버전: 1.0.0 (현재 stable)
6
6
 
7
7
  ## 1. 버전 해석
8
8
 
9
- 0.x 버전은 developer preview다. public exports는 사용 가능하지만, stable API 간주하지 않는다.
9
+ 0.x 라인은 developer preview였다: public exports는 사용 가능했지만 stable API **아니었다**. **1.0.0이 현재 stable 릴리스**이며, 아래 계약은 **지금 발효 중**이다 — Haechi는 이 계약을 선언하고 **strict semver**를 채택한다(§2 참조). §2의 freeze 규칙(frozen `exports`/CLI 표면, audit event schema, config key shape)은 릴리스된 1.0 라인에 적용되며, 더 이상 미래의 약속이 아니다. `tests/api-contract.test.mjs` freeze guard가 frozen 표면을 핀한다; frozen export·audit 필드·config key를 제거/이름 변경하면 CI가 실패한다(이것이 breaking change임을 의식적으로 알리는 신호다).
10
10
 
11
11
  | 버전 범위 | 의미 |
12
12
  |---|---|
13
- | `0.3.x` | local inference/proxy safety patch line |
14
- | `0.4.x` | token round-trip and adoption line |
15
- | `0.5.x` | streaming hardening target |
16
- | `0.6.x` | auth 및 운영 통제 target |
17
- | `1.0.0` | API compatibility contract를 선언할 있는 stable 후보 |
13
+ | `0.3.x` | local inference/proxy safety patch line (former preview) |
14
+ | `0.4.x` | token round-trip and adoption line (former preview) |
15
+ | `0.5.x` | streaming hardening target (former preview) |
16
+ | `0.6.x` | auth 및 운영 통제 target (former preview) |
17
+ | `0.7.x` – `0.9.x` | dashboard / KMS / OIDC 위성 + pre-1.0 하드닝 (former preview) |
18
+ | `1.0.0` | **현재 stable 릴리스.** §2의 API 계약이 strict semver 하에 frozen이며 발효 중이다. |
18
19
 
19
- ## 2. 변경 정책
20
+ ## 2. 1.0 안정성 계약
20
21
 
21
- | 변경 유형 | 0.x 처리 |
22
+ ### 2.1 Frozen public surface (IN / OUT)
23
+
24
+ 모든 `package.json` `exports` subpath과 CLI를 분류한다. 더 이상 "0.x는 preview"라는 암묵적 latitude는 없다.
25
+
26
+ | 표면 | 1.0 상태 |
27
+ |---|---|
28
+ | `haechi` / `haechi/core` — `createHaechi().protectJson`, `createHaechi().createStreamProtector`, `collectStringEntries`, `pathToString`, `safePathToString`, `shapeOnly`, `summarize` | **FROZEN** (breaking change = major) |
29
+ | `haechi/runtime` — `createRuntime`, `normalizeConfig` (config shape), `defaultConfig`, `loadConfig`, `writeDefaultConfig`, `isValidPort`, `DEFAULT_CONFIG_PATH` | **FROZEN** |
30
+ | `haechi/auth` — `authProvider` 계약, `buildIdentity`, `buildExternalIdentity`, `validateLabels`, `createBearerAuthProvider`, token store (`readAuthStore`, `addToken`, `listTokens`, `revokeToken`), `DEFAULT_ALLOWED_LABEL_KEYS` | **FROZEN** |
31
+ | `haechi/crypto` — `cryptoProvider` 계약, `assertCryptoProviderConformance`, `canonicalize`, `createLocalCryptoProvider`, `initLocalKeyFile` | **FROZEN** |
32
+ | `haechi/audit` — audit **event schema** (§2.3), `verifyAuditChain`, `sanitizeAudit`, `createJsonlAuditSink`, `readAuditSummary`, `FORBIDDEN_KEYS` | **FROZEN** |
33
+ | `haechi/policy` — `buildPolicy`, `createPolicyEngine`, `createPolicyProfiles`, `validatePolicy`, `ACTION_STRENGTH` (action ordering) | **FROZEN** |
34
+ | `haechi/filter` — `createDefaultFilterEngine`, `detectEntry`, 그리고 **rule/detection shape** | **FROZEN** |
35
+ | `haechi/token-vault` — `createLocalTokenVault`, `readVault`, token format, reveal-governance 계약 | **FROZEN** |
36
+ | `haechi/protocol-adapters` — `createProtocolAdapter`, `knownProtocolAdapters`, adapter classification 계약 | **FROZEN** |
37
+ | `haechi/plugin` — `validatePluginManifest`, `validatePluginManifestFile`, manifest schema, 1.0 signed-plugin sandbox 표면 | **FROZEN** |
38
+ | `haechi/proxy` — `createHaechiProxy`, `assertSafeProxyBind`, `DEFAULT_PROXY_PORT` | **FROZEN BEHAVIOR + wire/contract** (사람이 읽는 log/error **텍스트**는 변경 가능) |
39
+ | `haechi/mcp-stdio` — `protectMcpJsonRpcMessage`, `runMcpStdioFilter`, `wrapMcpChild` | **FROZEN BEHAVIOR + wire/contract** |
40
+ | `haechi/stream-filter` — `inspectResponseStream`, `getByPath`, `setByPath`, `buildPathObject` | **FROZEN BEHAVIOR + wire/contract** |
41
+ | `haechi/policy-bundle` — `signPolicyBundle(File)`, `verifyPolicyBundle(File)`, `loadVerifiedPolicyBundleFileSync` | **FROZEN BEHAVIOR + wire/contract** (signed-bundle 포맷 frozen) |
42
+ | `haechi/privacy-profiles` — `listPrivacyProfiles`, `getPrivacyProfile`, `applyPrivacyProfile` | **FROZEN BEHAVIOR + wire/contract** |
43
+ | **CLI** — `bin/haechi.mjs` 명령 이름, 플래그, **exit code**, 기계가 읽는(JSON) 출력 | **FROZEN BEHAVIOR + wire/contract**; 사람이 읽는 help/log/status **텍스트**는 계약이 아니며 변경 가능 |
44
+
45
+ **FROZEN** = export 이름·시그니처·동작이 major 버전 계약의 일부다. **FROZEN BEHAVIOR + wire/contract** = wire 포맷·exit code·기계가 읽는 출력·보안 동작은 frozen이지만, 사람이 읽는 CLI/log **텍스트**는 명시적으로 계약이 *아니며* minor/patch에서 변경될 수 있다.
46
+
47
+ ### 2.2 Strict semver + deprecation 정책
48
+
49
+ 1.0부터 "0.x minor가 깰 수 있다"는 latitude는 **끝난다**. 버저닝은 strict semver다:
50
+
51
+ | 변경 유형 | 릴리스 |
22
52
  |---|---|
23
- | 보안 기본값 강화 | patch에서 허용 |
24
- | unsafe config 차단 | patch에서 허용 |
25
- | export 제거/이름 변경 | minor에서 허용, README에 migration note 필요 |
26
- | policy action 의미 변경 | minor 이상 필요 |
27
- | audit schema 변경 | minor 이상 필요 |
28
- | crypto envelope format 변경 | minor 이상 필요, backward handling 필요 |
29
-
30
- ## 3. Experimental exports
31
-
32
- 다음 export는 0.4.0에서 preview로 취급한다.
33
-
34
- - `haechi/runtime`
35
- - `haechi/proxy`
36
- - `haechi/protocol-adapters`
37
- - `haechi/privacy-profiles`
38
- - `haechi/plugin`
39
- - `haechi/mcp-stdio` `wrapMcpChild`
40
- - `haechi/token-vault` `detokenize`, deterministic tokenization 옵션
41
- - `injection` detection type과 휴리스틱
42
- - `identity` audit 필드와 `authProvider` 계약 (0.4 예약, 0.6 구현 전까지 형태 변경 가능)
43
- - `status` / `audit-verify` CLI 출력 형태
44
- - `haechi/stream-filter` (`inspectResponseStream`, path helpers) `createStreamProtector` (스트리밍 검사 내부 구현)
45
- - `haechi/auth` (`createBearerAuthProvider`, token store, `buildIdentity`, `buildExternalIdentity`) `authProvider` 계약
46
- - `policy.profiles`/`policy.profileBinding`/`modelAllowlist`/`rate` 및 `identity`/`profile` audit 필드
47
- - `assertCryptoProviderConformance` 및 강화된 cryptoProvider 계약 (envelope base shape + provider 확장)
48
- - `audit.anchor` 설정 및 `verifyAuditChain(path, { anchorPath })`
49
- - `scripts/release-checksums.mjs` (SHA256SUMS 생성/검증)
53
+ | Breaking change (frozen export·필드·config key 제거/이름 변경; frozen 시그니처·wire 포맷 변경) | **major** |
54
+ | Additive change (새 export, 새 optional config key, additive audit 필드) | **minor** |
55
+ | Bug fix / default 하드닝 (shape 변경 없음) | **patch** |
56
+
57
+ **Deprecation 정책.** deprecated된 export / audit 필드 / config 옵션은:
58
+
59
+ 1. deprecation 후 **최소 1 minor 동안 유지**되고,
60
+ 2. **문서화된 migration note**(`docs/current/release-*.md` 또는 README)와 함께 배포되며,
61
+ 3. **안정 `code` prefix `HAECHI_DEPRECATION_*`**(예: `HAECHI_DEPRECATION_CONFIG_<key>`, `HAECHI_DEPRECATION_EXPORT_<name>`)를 가진 **일회성 런타임 `process.emitWarning`**를 발생시킨다. **경고 `code`와 그 텍스트 자체가 계약의 일부다** — 소비자가 매칭할 수 있는 안정 식별자이며, 다음 major에서만 변경된다.
62
+
63
+ deprecated 표면은 **다음 major에서만 제거**된다.
64
+
65
+ **보안 예외 (허용되는 단 하나의 in-minor break).** **공개된(disclosed)** 취약점을 닫기 위해 필요한 변경은 **minor 안에서** frozen 표면을 깨거나 제거할 수 있으며, **보안 권고(advisory) + migration path**와 함께 배포된다. 이는 오래된 "unsafe config 차단은 patch에서 강화 가능" latitude를 그대로 반영한다 — 보안 태세는 deprecation 창보다 빠르게 강화될 수 있다.
66
+
67
+ ### 2.3 Frozen audit event schema (중첩 sub-schema 포함)
68
+
69
+ audit event(`packages/core/index.mjs`의 `buildAuditEvent`가 생성, `packages/audit`가 무결성 스탬프)는 top-level뿐 아니라 **중첩 sub-schema까지** frozen이다:
70
+
71
+ - **top-level**: `{ schemaVersion, id, timestamp, protocol, operation, identity, profile, mode, enforced, blocked, payloadShapeHash, detections, summary, auditIntegrity }`
72
+ - `detections[]`: `{ type, ruleId, path, kind, confidence, action, enforced }`
73
+ - `identity` (**PII-safe** 투영): `{ id, type, subjectHash, issuerHash, provider }` — `scopes` / `labels` / raw subject은 frozen audit identity의 **일부가 아니다**(keyed-HMAC `subjectHash`/`issuerHash`가 유일한 subject/issuer 표면이다). 단, 실제 온디스크 `identity` 객체에는 `scopes`와 `labels`가 함께 포함될 수 있어 총 7개의 키를 가질 수 있으나, 해당 필드들은 frozen 계약의 **일부가 아니다** — audit 로그 소비자는 이 필드들의 존재에 의존해서는 안 된다. auth 미설정 시 `identity`는 `null`이다.
74
+ - `summary`: `{ byType, byAction, detectionCount }`
75
+ - `auditIntegrity`: `{ alg, canonicalization, sequence, previousHash, eventHash }`
76
+
77
+ 규칙:
78
+
79
+ - **`schemaVersion`**은 명시적 top-level reader-facing 필드(1.0 라인에서 값 `"1"`)로, 소비자가 `auditIntegrity`를 파싱하지 않고도 분기할 수 있게 한다. **additive**이며 canonicalize 대상 객체의 일부다.
80
+ - **새 필드는 additive-only이고 기존 필드의 canonicalization을 절대 바꾸지 않는다.** `canonicalize`는 리터럴 객체를 해싱하고 `verifyAuditChain`은 *동일한* 저장 객체로 `eventHash`를 재계산하므로, future-additive 필드를 담은 1.x event도 그 레코드를 읽는 1.0 `verifyAuditChain` 하에서 여전히 검증된다 — 보장은 "future-additive 필드가 새 레코드를 읽는 옛 verifier를 깨뜨리지 않는다"이다.
81
+ - **canonicalization 변경**은 **major** event-schema bump다: **새 `canonicalization` 태그**(현재 값 `json-stable-v1`)와 **reader-migration path**를 함께 배포한다. 기존 필드의 해시 기반이 바뀔 수 있는 유일한 방법이다.
82
+
83
+ ### 2.4 Config schema freeze 단위
84
+
85
+ **config key 존재 + shape**가 frozen이다(top-level key `mode`, `target`, `proxy`, `responseProtection`, `streaming`, `limits`, `policy`, `filters`, `keys`, `audit`, `tokenVault`, `privacy`, `auth`, `mcp` 및 그 중첩 shape). **default *값*은 여전히 하드닝될 수 있다** — 더 안전한 default(예: 더 엄격한 `failureMode`)는 breaking change가 **아니다**. **알 수 없는 key는 여전히 throw한다**(fail-closed): `normalizeConfig`는 엄격한 enumerated 검증을 수행하며, 그 fail-closed 태세가 계약의 일부다.
86
+
87
+ ## 3. Graduated / 잔존 preview exports
88
+
89
+ 0.x "experimental exports" 목록은 1.0에서 **해소**된다 — 모든 항목은 **graduated**(이제 §2.1 FROZEN / FROZEN-BEHAVIOR 표면의 일부)되거나 명시적 이유와 함께 **1.0 이후에도 preview로 유지**된다. 암묵적 모호함은 없다.
90
+
91
+ **Graduated (이제 §2.1에 따라 FROZEN):** `haechi/runtime`, `haechi/proxy`, `haechi/protocol-adapters`, `haechi/privacy-profiles`, `haechi/plugin`, `haechi/mcp-stdio` (`wrapMcpChild`), `haechi/token-vault` (`detokenize` / deterministic tokenization 옵션), `identity` audit 필드와 `authProvider` 계약, `haechi/stream-filter`와 `createStreamProtector`, `haechi/auth` (`createBearerAuthProvider`, token store, `buildIdentity`, `buildExternalIdentity`), `assertCryptoProviderConformance`와 강화된 `cryptoProvider` 계약, `audit.anchor` + `verifyAuditChain(path, { anchorPath })`, `scripts/release-checksums.mjs`, `policy.profiles` / `policy.profileBinding` / `modelAllowlist` / `rate`와 `identity` / `profile` audit 필드. `status` / `audit-verify` CLI 출력의 기계가 읽는 형태는 frozen이다(FROZEN BEHAVIOR — 사람이 읽는 텍스트는 아님).
92
+
93
+ **1.0 이후에도 preview로 유지 (이유 명시):**
94
+
95
+ - **`injection` detection type과 그 휴리스틱 룰** — 휴리스틱 집합은 계속 진화할 것으로 예상되며 **기본 report-only**다(명시적 escalate 없이는 response 방향에서 action `allow`로 고정). 따라서 그 *룰 멤버십 / confidence*는 frozen이 아니지만, 그것이 생성하는 detection *shape*는 frozen `detections[]` shape다. `injection` 룰 추가/변경은 breaking change가 아니다.
50
96
 
51
97
  ## 4. Migration note 기준
52
98
 
53
- 다음 변경이 있으면 `docs/current/release-*.md` 또는 README에 migration note를 남긴다.
99
+ 다음 변경이 있으면 `docs/current/release-*.md` 또는 README에 migration note를 남긴다. 1.0부터 이 목록의 변경이 **FROZEN** 표면에 가해지면 **major** 이벤트(또는 §2.2의 보안 예외 minor)이며, deprecation 창이 적용되는 경우 `HAECHI_DEPRECATION_*` 런타임 경고를 동반하고 `tests/api-contract.test.mjs`를 갱신한다.
54
100
 
55
101
  - config key 추가/삭제
56
102
  - default enforcement 변경
57
103
  - CLI flag 추가/삭제
58
- - audit event 필드 변경
104
+ - audit event 필드 변경 (top-level 또는 중첩)
59
105
  - token format 변경
60
106
  - plugin manifest schema 변경
61
107
 
@@ -64,7 +110,7 @@
64
110
  위성(예: `haechi-crypto-kms`, `haechi-auth-jwt`, `haechi-dashboard`, `haechi-auth-oidc`)은 core와 **독립적으로** 버저닝한다 — 위성 릴리스가 `haechi`를 bump하지 않고, 그 반대도 마찬가지다.
65
111
 
66
112
  - **pre-1.0:** 위성은 npm semver를 따르며 `0.x` **minor** bump가 breaking change를 담을 수 있다; `major.minor`로 핀한다(예: `haechi-crypto-kms@~0.2`). 각자 자체 `1.0.0`까지 pre-stable.
67
- - **core 호환성**은 `peerDependencies` 범위(`"haechi": ">=0.8.0 <1.0.0"`)로 표현한다 — 위성은 소비자가 설치한 단일 `haechi`를 재사용하므로 crypto/identity 표면이 하나다. `haechi-auth-oidc`는 추가로 `haechi-auth-jwt`(`">=0.2.0 <1.0.0"`)에 peer-depend하여 둘이 audit되는 단일 JWS/JWKS 검증 경로를 공유한다.
113
+ - **core 호환성**은 `peerDependencies` 범위(`"haechi": ">=0.8.0 <2.0.0"`)로 표현한다 — 위성은 소비자가 설치한 단일 `haechi`를 재사용하므로 crypto/identity 표면이 하나다. `haechi-auth-oidc`는 추가로 `haechi-auth-jwt`(`">=0.2.0 <2.0.0"`)에 peer-depend하여 둘이 audit되는 단일 JWS/JWKS 검증 경로를 공유한다. 위성의 `haechi` peer-dependency **상한은 반드시 core MAJOR를 추적해야 하며**(`<2.0.0`), 다음 minor 미만으로 고정해서는 안 된다 — core의 minor/major 호환 범프가 위성 설치를 깨뜨리지 않도록 하기 위함이다; `release:preflight` 게이트(`scripts/check-satellite-peer-ranges.mjs`)가 이를 자동으로 강제한다.
68
114
  - **무거운 백엔드는 optional peer다.** `haechi-crypto-kms`는 SDK 백엔드(`@aws-sdk/client-kms`, 그리고 0.2.0의 `@google-cloud/kms`, `@azure/keyvault-keys`, `@azure/identity`)를 `peerDependencies` + `peerDependenciesMeta.optional`로 선언하고 lazy import하므로, 해당 경로를 쓰지 않는 소비자는 설치하지 않고 core는 zero-dependency를 유지한다. `./vault` 백엔드는 `node:` `fetch`만 사용한다(optional peer 없음). 위성의 배포 tarball은 항상 **runtime `dependencies` 0**을 선언한다(CI `check-satellite-packaging`로 강제).
69
115
  - **pre-1.0 위성 export**는 preview이며 각 위성의 자체 `1.0.0` 전에 변경될 수 있다:
70
116
  - `haechi-crypto-kms` (0.8 → 0.2.0): `createKmsCryptoProvider`, `createInMemoryKms`, `./aws`의 `createAwsKmsClient`, 그리고 0.2.0의 새 subpath `./gcp`(`createGcpKmsClient`), `./azure`(`createAzureKmsClient`), `./vault`(`createVaultKmsClient`).
@@ -1,61 +1,107 @@
1
1
  # Haechi API Stability Policy
2
2
 
3
- - Status: Draft 0.1
4
- - Date: 2026-06-10
5
- - Target version: 0.7.0
3
+ - Status: In effect (1.0 contract — the API freeze)
4
+ - Date: 2026-06-11
5
+ - Applies to version: 1.0.0 (current stable)
6
6
 
7
7
  ## 1. Version Interpretation
8
8
 
9
- 0.x releases are developer previews. Public exports are available for use but are not considered stable API.
9
+ The 0.x line was a developer preview: public exports were usable but **not** a stable API. **1.0.0 is the current stable release**, and the contract below is **in effect now** — Haechi declares this contract and adopts **strict semver** (see §2). The freeze rules in §2 (the frozen `exports`/CLI surface, the audit event schema, and the config key shape) apply to the 1.0 line as released; they are no longer a future commitment. The `tests/api-contract.test.mjs` freeze guard pins the frozen surface; a removed/renamed frozen export, audit field, or config key fails CI (the conscious signal of a breaking change).
10
10
 
11
11
  | Version range | Meaning |
12
12
  |---|---|
13
- | `0.3.x` | local inference/proxy safety patch line |
14
- | `0.4.x` | token round-trip and adoption line |
15
- | `0.5.x` | streaming hardening target |
16
- | `0.6.x` | auth and operational controls target |
17
- | `1.0.0` | First stable candidate at which an API compatibility contract may be declared |
13
+ | `0.3.x` | local inference/proxy safety patch line (former preview) |
14
+ | `0.4.x` | token round-trip and adoption line (former preview) |
15
+ | `0.5.x` | streaming hardening target (former preview) |
16
+ | `0.6.x` | auth and operational controls target (former preview) |
17
+ | `0.7.x` – `0.9.x` | dashboard / KMS / OIDC satellites + pre-1.0 hardening (former preview) |
18
+ | `1.0.0` | **Current stable release.** The API contract in §2 is frozen and in effect under strict semver. |
18
19
 
19
- ## 2. Change Policy
20
+ ## 2. The 1.0 stability contract
20
21
 
21
- | Change type | 0.x handling |
22
+ ### 2.1 Frozen public surface (IN / OUT)
23
+
24
+ Every `package.json` `exports` subpath and the CLI is classed. There is no silent "0.x is preview" latitude anymore.
25
+
26
+ | Surface | 1.0 status |
27
+ |---|---|
28
+ | `haechi` / `haechi/core` — `createHaechi().protectJson`, `createHaechi().createStreamProtector`, `collectStringEntries`, `pathToString`, `safePathToString`, `shapeOnly`, `summarize` | **FROZEN** (breaking change = major) |
29
+ | `haechi/runtime` — `createRuntime`, `normalizeConfig` (config shape), `defaultConfig`, `loadConfig`, `writeDefaultConfig`, `isValidPort`, `DEFAULT_CONFIG_PATH` | **FROZEN** |
30
+ | `haechi/auth` — the `authProvider` contract, `buildIdentity`, `buildExternalIdentity`, `validateLabels`, `createBearerAuthProvider`, the token store (`readAuthStore`, `addToken`, `listTokens`, `revokeToken`), `DEFAULT_ALLOWED_LABEL_KEYS` | **FROZEN** |
31
+ | `haechi/crypto` — the `cryptoProvider` contract, `assertCryptoProviderConformance`, `canonicalize`, `createLocalCryptoProvider`, `initLocalKeyFile` | **FROZEN** |
32
+ | `haechi/audit` — the audit **event schema** (§2.3), `verifyAuditChain`, `sanitizeAudit`, `createJsonlAuditSink`, `readAuditSummary`, `FORBIDDEN_KEYS` | **FROZEN** |
33
+ | `haechi/policy` — `buildPolicy`, `createPolicyEngine`, `createPolicyProfiles`, `validatePolicy`, `ACTION_STRENGTH` (action ordering) | **FROZEN** |
34
+ | `haechi/filter` — `createDefaultFilterEngine`, `detectEntry`, and the **rule/detection shape** | **FROZEN** |
35
+ | `haechi/token-vault` — `createLocalTokenVault`, `readVault`, the token format, and the reveal-governance contract | **FROZEN** |
36
+ | `haechi/protocol-adapters` — `createProtocolAdapter`, `knownProtocolAdapters`, and the adapter classification contract | **FROZEN** |
37
+ | `haechi/plugin` — `validatePluginManifest`, `validatePluginManifestFile`, the manifest schema, and the 1.0 signed-plugin sandbox surface | **FROZEN** |
38
+ | `haechi/proxy` — `createHaechiProxy`, `assertSafeProxyBind`, `DEFAULT_PROXY_PORT` | **FROZEN BEHAVIOR + wire/contract** (human-readable log/error **text** may change) |
39
+ | `haechi/mcp-stdio` — `protectMcpJsonRpcMessage`, `runMcpStdioFilter`, `wrapMcpChild` | **FROZEN BEHAVIOR + wire/contract** |
40
+ | `haechi/stream-filter` — `inspectResponseStream`, `getByPath`, `setByPath`, `buildPathObject` | **FROZEN BEHAVIOR + wire/contract** |
41
+ | `haechi/policy-bundle` — `signPolicyBundle(File)`, `verifyPolicyBundle(File)`, `loadVerifiedPolicyBundleFileSync` | **FROZEN BEHAVIOR + wire/contract** (the signed-bundle format is frozen) |
42
+ | `haechi/privacy-profiles` — `listPrivacyProfiles`, `getPrivacyProfile`, `applyPrivacyProfile` | **FROZEN BEHAVIOR + wire/contract** |
43
+ | **CLI** — `bin/haechi.mjs` command names, flags, **exit codes**, and machine-readable (JSON) output | **FROZEN BEHAVIOR + wire/contract**; human-readable help/log/status **text** may still change (not part of the contract) |
44
+
45
+ **FROZEN** = the export name, signature, and behavior are part of the major-versioned contract. **FROZEN BEHAVIOR + wire/contract** = the wire format, exit codes, machine-readable output, and security behavior are frozen, but the human-readable CLI/log **text** is explicitly *not* part of the contract and may change in a minor/patch.
46
+
47
+ ### 2.2 Strict semver + deprecation policy
48
+
49
+ From 1.0 the "0.x minor may break" latitude **ends**. Versioning is strict semver:
50
+
51
+ | Change type | Release |
22
52
  |---|---|
23
- | Strengthening security defaults | Allowed in patch |
24
- | Blocking unsafe config | Allowed in patch |
25
- | Removing or renaming exports | Allowed in minor; migration note required in README |
26
- | Changing policy action semantics | Requires minor or higher |
27
- | Changing audit schema | Requires minor or higher |
28
- | Changing crypto envelope format | Requires minor or higher; backward handling required |
29
-
30
- ## 3. Experimental exports
31
-
32
- The following exports are treated as preview in 0.4.0.
33
-
34
- - `haechi/runtime`
35
- - `haechi/proxy`
36
- - `haechi/protocol-adapters`
37
- - `haechi/privacy-profiles`
38
- - `haechi/plugin`
39
- - `haechi/mcp-stdio` `wrapMcpChild`
40
- - `haechi/token-vault` `detokenize`, deterministic tokenization options
41
- - `injection` detection type and its heuristic rules
42
- - `identity` audit field and the `authProvider` contract (reserved in 0.4, implemented in 0.6 — shape may change until then)
43
- - `status` / `audit-verify` CLI output shapes
44
- - `haechi/stream-filter` (`inspectResponseStream`, path helpers) and `createStreamProtector` (streaming inspection internals)
45
- - `haechi/auth` (`createBearerAuthProvider`, token store, `buildIdentity`, `buildExternalIdentity`) and the `authProvider` contract
46
- - `assertCryptoProviderConformance` and the hardened cryptoProvider contract (envelope base shape + provider extensions)
47
- - `audit.anchor` config and `verifyAuditChain(path, { anchorPath })`
48
- - `scripts/release-checksums.mjs` (SHA256SUMS generate/verify)
49
- - `policy.profiles`/`policy.profileBinding`/`modelAllowlist`/`rate` and the `identity`/`profile` audit fields
53
+ | Breaking change (remove/rename a frozen export, field, or config key; change a frozen signature or wire format) | **major** |
54
+ | Additive change (new export, new optional config key, new additive audit field) | **minor** |
55
+ | Bug fix / hardening a default value (no shape change) | **patch** |
56
+
57
+ **Deprecation policy.** A deprecated export / audit field / config option is:
58
+
59
+ 1. **kept for ≥ 1 minor** after deprecation,
60
+ 2. shipped with a **documented migration note** (in `docs/current/release-*.md` or the README), and
61
+ 3. wired to emit a **one-time runtime `process.emitWarning`** with a **stable `code` prefix `HAECHI_DEPRECATION_*`** (e.g. `HAECHI_DEPRECATION_CONFIG_<key>`, `HAECHI_DEPRECATION_EXPORT_<name>`). **The warning `code` and its text are themselves part of the contract** — they are stable identifiers a consumer may match, and they only change at the next major.
62
+
63
+ The deprecated surface is **removed only at the next major**.
64
+
65
+ **Security exception (the one sanctioned in-minor break).** A change required to close a **disclosed** vulnerability may break or remove a frozen surface **within a minor**, shipped with a **security advisory + a migration path**. This mirrors the long-standing "blocking unsafe config may tighten in a patch" latitude — the security posture is allowed to harden faster than the deprecation window.
66
+
67
+ ### 2.3 Frozen audit event schema (including nested sub-schemas)
68
+
69
+ The audit event (built in `packages/core/index.mjs` `buildAuditEvent`, integrity-stamped by `packages/audit`) is frozen **including its nested sub-schemas**, not just the top level:
70
+
71
+ - **top-level**: `{ schemaVersion, id, timestamp, protocol, operation, identity, profile, mode, enforced, blocked, payloadShapeHash, detections, summary, auditIntegrity }`
72
+ - `detections[]`: `{ type, ruleId, path, kind, confidence, action, enforced }`
73
+ - `identity` (the **PII-safe** projection): `{ id, type, subjectHash, issuerHash, provider }` — `scopes` / `labels` / a raw subject are **NOT** part of the frozen audit identity (the keyed-HMAC `subjectHash`/`issuerHash` are the only subject/issuer surface). Note: the on-disk `identity` object MAY also carry `scopes` and `labels` (7 keys total), but those fields are **not** part of the frozen contract — a consumer of the audit log must not depend on their presence. `identity` is `null` when no auth is configured.
74
+ - `summary`: `{ byType, byAction, detectionCount }`
75
+ - `auditIntegrity`: `{ alg, canonicalization, sequence, previousHash, eventHash }`
76
+
77
+ Rules:
78
+
79
+ - **`schemaVersion`** is an explicit top-level reader-facing field (value `"1"` in the 1.0 line) so consumers branch on it without parsing `auditIntegrity`. It is **additive** and is part of the canonicalized object.
80
+ - **New fields are additive-only and never change the canonicalization of existing fields.** Because `canonicalize` hashes the literal object and `verifyAuditChain` recomputes `eventHash` over the *same* stored object, a 1.x event carrying a future-additive field still verifies under a 1.0 `verifyAuditChain` reading that record — the guarantee is "a future-additive field doesn't break an old verifier reading a new record."
81
+ - A **canonicalization change** is a **major** event-schema bump: it ships a **new `canonicalization` tag** (the current value is `json-stable-v1`) **plus a reader-migration path**. It is the only way the hash basis of existing fields may change.
82
+
83
+ ### 2.4 Config schema freeze unit
84
+
85
+ The **config key presence + shape** is frozen (the top-level keys `mode`, `target`, `proxy`, `responseProtection`, `streaming`, `limits`, `policy`, `filters`, `keys`, `audit`, `tokenVault`, `privacy`, `auth`, `mcp`, and their nested shapes). **Default *values* may still be hardened** — a safer default (e.g. a stricter `failureMode`) is **not** a breaking change. **Unknown keys still throw** (fail-closed): `normalizeConfig` performs strict, enumerated validation, and that fail-closed posture is part of the contract.
86
+
87
+ ## 3. Graduated / remaining-preview exports
88
+
89
+ The 0.x "experimental exports" list is **resolved** at 1.0 — every entry is either **graduated** (now part of the §2.1 FROZEN / FROZEN-BEHAVIOR surface) or explicitly **kept preview past 1.0** with a stated reason. There is no silent ambiguity.
90
+
91
+ **Graduated (now FROZEN per §2.1):** `haechi/runtime`, `haechi/proxy`, `haechi/protocol-adapters`, `haechi/privacy-profiles`, `haechi/plugin`, `haechi/mcp-stdio` (`wrapMcpChild`), `haechi/token-vault` (`detokenize` / deterministic tokenization options), the `identity` audit field and the `authProvider` contract, `haechi/stream-filter` and `createStreamProtector`, `haechi/auth` (`createBearerAuthProvider`, token store, `buildIdentity`, `buildExternalIdentity`), `assertCryptoProviderConformance` and the hardened `cryptoProvider` contract, `audit.anchor` + `verifyAuditChain(path, { anchorPath })`, `scripts/release-checksums.mjs`, and `policy.profiles` / `policy.profileBinding` / `modelAllowlist` / `rate` with the `identity` / `profile` audit fields. The machine-readable shape of `status` / `audit-verify` CLI output is frozen (FROZEN BEHAVIOR — the human-readable text is not).
92
+
93
+ **Kept preview past 1.0 (with reason):**
94
+
95
+ - The **`injection` detection type and its heuristic rules** — the heuristic set is expected to keep evolving and is **report-only by default** (it pins action `allow` on the response direction unless explicitly escalated), so its *rule membership / confidence* is not frozen, though the detection *shape* it produces is the frozen `detections[]` shape. New/changed `injection` rules are not a breaking change.
50
96
 
51
97
  ## 4. Migration note criteria
52
98
 
53
- A migration note is added to `docs/current/release-*.md` or the README whenever any of the following changes occur.
99
+ A migration note is added to `docs/current/release-*.md` or the README whenever any of the following changes occur. From 1.0, a change in this list to a **FROZEN** surface is a **major** event (or a security-exception minor per §2.2), carries the `HAECHI_DEPRECATION_*` runtime warning where a deprecation window applies, and updates `tests/api-contract.test.mjs`.
54
100
 
55
101
  - Adding or removing a config key
56
102
  - Changing default enforcement behavior
57
103
  - Adding or removing a CLI flag
58
- - Changing an audit event field
104
+ - Changing an audit event field (top-level OR nested)
59
105
  - Changing the token format
60
106
  - Changing the plugin manifest schema
61
107
 
@@ -64,7 +110,7 @@ A migration note is added to `docs/current/release-*.md` or the README whenever
64
110
  Satellites (e.g. `haechi-crypto-kms`, `haechi-auth-jwt`, `haechi-dashboard`, `haechi-auth-oidc`) version **independently** of core — a satellite release never bumps `haechi`, and vice versa.
65
111
 
66
112
  - **Pre-1.0:** satellites follow npm semver where a `0.x` **minor** bump may carry breaking changes; pin `major.minor` (e.g. `haechi-crypto-kms@~0.2`). Each is pre-stable until its own `1.0.0`.
67
- - **Core compatibility** is expressed as a `peerDependencies` range (`"haechi": ">=0.8.0 <1.0.0"`) — a satellite reuses the consumer's single installed `haechi`, so there is one crypto/identity surface. `haechi-auth-oidc` additionally peer-depends on `haechi-auth-jwt` (`">=0.2.0 <1.0.0"`) so the two share one audited JWS/JWKS verification path.
113
+ - **Core compatibility** is expressed as a `peerDependencies` range (`"haechi": ">=0.8.0 <2.0.0"`) — a satellite reuses the consumer's single installed `haechi`, so there is one crypto/identity surface. `haechi-auth-oidc` additionally peer-depends on `haechi-auth-jwt` (`">=0.2.0 <2.0.0"`) so the two share one audited JWS/JWKS verification path. The satellite `haechi` peer-dependency **upper bound must track the core MAJOR** (`<2.0.0`), never be pinned below the next minor, so a core minor- or major-compatible bump never breaks satellite installs; the `release:preflight` gate (`scripts/check-satellite-peer-ranges.mjs`) enforces this automatically.
68
114
  - **Heavy backends are optional peers.** `haechi-crypto-kms` declares its SDK backends (`@aws-sdk/client-kms`, and in 0.2.0 `@google-cloud/kms`, `@azure/keyvault-keys`, `@azure/identity`) under `peerDependencies` + `peerDependenciesMeta.optional` and imports them lazily, so consumers who do not use a given path never install it and core stays zero-dependency. The `./vault` backend uses `node:` `fetch` only (no optional peer). A satellite's published tarball always declares **zero runtime `dependencies`** (CI-gated by `check-satellite-packaging`).
69
115
  - **Pre-1.0 satellite exports** are preview and may change before each satellite's own `1.0.0`:
70
116
  - `haechi-crypto-kms` (0.8 → 0.2.0): `createKmsCryptoProvider`, `createInMemoryKms`, the `./aws` `createAwsKmsClient`, and the new 0.2.0 subpaths `./gcp` (`createGcpKmsClient`), `./azure` (`createAzureKmsClient`), `./vault` (`createVaultKmsClient`).