<a id="configuration-contract"></a>
# 설정 계약과 우선순위

ARTEX 설정은 실행 flag, process 환경변수, `config.json`, PostgreSQL `settings`, LLM profile, agent/task override로 나뉜다. 저장 위치가 같아도 읽는 시점과 적용 방식은 다르다. 전체 이름·타입·기본값·소비자는 [런타임 설정 전수표](runtime-settings.md#runtime-settings-reference), 빌드와 배포 입력은 [의존성·빌드 계약](dependencies.md#build-contract)을 본다. [config loader](evidence:config)

```mermaid
flowchart LR
  CLI[process flags] --> Boot[process bootstrap]
  Env[environment] --> Boot
  File[config.json] --> Boot
  Settings[(settings)] --> Runtime[manager / scheduler / interceptor]
  Profiles[(LLM profiles)] --> Provider[provider chain]
  Agent[agent + task overrides] --> Provider
  Runtime --> Rebuild{apply 경계}
  Rebuild -->|즉시/다음 tick| Live[현재 process]
  Rebuild -->|agent 재조립| Sessions[이후 session/run]
```

<a id="startup-flags"></a>
## 시작 flag

실행 파일이 직접 등록하는 애플리케이션 flag는 3개다. Go `flag`가 제공하는 `-h`/`-help`는 도움말을 출력하고 성공 종료한다. [main](evidence:main)

| flag | 타입·기본값 | 소비 시점 | 효과 |
|---|---|---|---|
| `-addr` | string, `:8787` | HTTP server 시작 | API와 embedded UI listen address |
| `-data` | path string, `<BaseDir>/data` | manager/store 생성 | traffic SQLite·body/blob·evidence·transcript·task workspace root |
| `-proxy` | address string, `127.0.0.1:8788` | manager 생성 | recording proxy listen address; 빈 문자열이면 proxy를 만들지 않음 |

`start.sh`와 `start.bat`는 인자를 그대로 binary에 전달한다. `go run`의 임시 executable은 `BaseDir()`가 감지해 CWD를 기준으로 되돌린다. supervisor의 종료 코드 계약은 [시작 wrapper](../operations.md#start-wrapper)에 있다. [start wrapper](evidence:start-script)

<a id="file-env-precedence"></a>
## 부팅 설정 우선순위

| 목적 | 높은 순서 | 기본·실패 |
|---|---|---|
| config path | `ARTEX_CONFIG` → CWD `config.json` → executable 옆 `config.json` | 파일이 없으면 CWD 후보를 진단 path로 반환 |
| PostgreSQL DSN | `ARTEX_PG_DSN` → `database.dsn` → `database.*` 조립 | 유효한 입력이 없으면 startup 실패 |
| skill root | `ARTEX_SKILL_DIR` → `skill_dir` → `<BaseDir>/skills` | directory 생성을 시도하며 생성 오류는 이 helper가 반환하지 않음 |
| 기본 LLM fallback | DB profile/agent/task binding 경로 → LLM 환경변수 | provider와 key를 해석하지 못하면 fallback provider 없음 |

`config.json` 읽기 또는 JSON decode 실패는 오류를 반환하지 않고 zero config가 된다. 알 수 없는 JSON field도 무시된다. 따라서 “파일이 있다”는 사실은 DSN이 유효하다는 뜻이 아니다. `config.example.json`의 port `5433`은 예시 값이고 field 조립의 코드 기본은 `5432`다. [config](evidence:config) [example](evidence:config-example)

<a id="runtime-settings"></a>
## 런타임 설정 분모

현재 source에서 운영자가 조절하는 설정 계약은 다음처럼 따로 센다. 내부 seed/migration marker는 입력 분모에 섞지 않는다.

| 계열 | 수 | 전수표 |
|---|---:|---|
| binary application flag | 3 | [CLI](runtime-settings.md#runtime-cli) |
| Go application runtime env | 13 | [process 환경변수](runtime-settings.md#runtime-env) |
| dependency-owned explicit runtime env | 6 | [Norma provider/tool 입력](runtime-settings.md#dependency-env) |
| `config.json` field | 8 | [파일 schema](runtime-settings.md#config-json) |
| operator-managed `settings` key | 31 | [DB 런타임 키](runtime-settings.md#operator-settings) |
| internal seed/migration marker | 24 | [내부 marker](runtime-settings.md#internal-setting-markers) |

별도 분모인 frontend/build/Compose 환경변수와 script option은 [빌드 입력](dependencies.md#build-contract)과 [정상 운영 명령](../operations.md#command-index)에 있다. `settings`의 31개는 일반 설정 API의 21개 field뿐 아니라 intercept 1개, judge 7개, global retry 1개, 관리자 password hash 1개를 포함한다. [manager settings](evidence:manager)

<a id="task-agent-overrides"></a>
## Profile·agent·task override

Process LLM 환경변수는 fallback 하나를 만든다. DB profile이 있으면 active/default profile, agent profile binding, task의 ordered profile chain, pool/fallback 설정이 provider 선택에 참여한다. `llm_retry_policy`의 connect/empty/stream 값 위에는 profile별 field override가 올라가고, breaker/intent는 global 값만 쓴다. 이 계층은 `config.json` field가 아니다. [provider routing](../modules/agent-runtime.md#provider-routing)

Tool·MCP·Skill 노출도 agent visibility와 `tools.agents`, enabled, deferred 상태가 합성한다. 이름과 역할별 기본 집합은 [도구 전수표](tool-catalog.md#tool-catalog-reference)에 있다.

<a id="config-apply-boundary"></a>
## 저장과 적용 경계

| 적용 경계 | 해당 값 | 의미 |
|---|---|---|
| process 재시작 | CLI, `config.json`, Go runtime env, Norma env gate | 부팅 때 다시 읽음 |
| agent/provider 재조립 | traffic, global proxy, web search, LLM pool, retry의 provider 계층 | settings handler가 `applyLLM`/profile invalidation을 수행; 이미 진행 중인 turn의 원자적 교체를 뜻하지 않음 |
| 다음 run/task | `workers`, `noa_compaction` | 새 engine run이 다시 읽음 |
| 즉시 또는 다음 scheduler tick | task concurrency, `llm_record`, constraint injection, notify | in-memory 값 갱신, 매 호출/매 round/매 tick 재조회 |
| 다음 intercept 판정 | enabled tool set, judge config | cache invalidation 또는 판정 시 fresh read |

`global_proxy`는 egress route이고 scope authorization은 아니다. `llm_record`는 request/response와 tool schema를 저장할 수 있으며 기본값은 false다. secret 값은 환경변수, `settings`, LLM profile에 흩어질 수 있으므로 문서나 운영 dump에 실제 값을 복사하지 않는다.
