Skip to content

Commit f40d1ae

Browse files
committed
Make the semantic runtime legible and CI-ready for first review
Names the public flow by its actual lazy-review behavior and applies the repository-pinned formatter so the consolidated branch passes its existing all-files hook. Constraint: Keep internal governed_* contracts stable while making the user-facing feature and handoff intuitive. Rejected: Rename internal APIs and symbols | compatibility risk without user-facing benefit. Confidence: high Scope-risk: narrow Directive: Keep public copy aligned with candidate-before-review behavior and verified dialect limits. Tested: 355 pytest cases; Ruff; mypy 97 files; Black 129 files; offline quickstart; Markdown links; formatting AST equality. Not-tested: Live Discord transport and unverified remote dialect execution.
1 parent c8e9845 commit f40d1ae

26 files changed

Lines changed: 224 additions & 276 deletions

README.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
> *separate* set of definitions per team → it answers questions over an
2222
> incomplete database → it remembers every definition and conversation.
2323
24-
연결된 DB에 **governed semantic mode**가 활성화되면 모델은 SQL을 작성하지 않는다.
25-
모델은 사람이 검토한 지표·분류·필터 후보만 고르고, 결정론적 코드가 검증된 SQL을
26-
컴파일한다.
24+
연결된 DB에 **업무 의미 검토형 질의**가 활성화되면 모델은 SQL을 작성하지 않는다.
25+
모델은 서버가 질문별로 제한한 후보만 고르고, 실행에 필요한 불확실한 업무 의미를
26+
사람이 확인한 뒤 결정론적 코드가 검증된 SQL을 컴파일한다.
2727

2828
👉 **프로젝트 전체 그림(단일 SSOT)**: [`docs/PROJECT.md`](docs/PROJECT.md) · **컨트리뷰터 한눈 가이드**: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
2929

@@ -41,7 +41,7 @@ interface, not the identity** — Slack/Web are adapters on the same core.
4141
| **Candidate** | 모델이나 UI가 고를 수 있도록 서버가 질문별로 제한한 지표·분류·필터·기간 후보 |
4242
| **Human review** | 불확실한 업무 의미나 데이터 공개 범위를 사람이 명시적으로 승인·거절하는 단계 |
4343
| **Typed plan** | SQL 문자열 대신 metric, aggregate, group-by, filter, date 범위를 구조화한 검증 대상 |
44-
| **Governed mode** | semantic catalog가 활성화되어 모델의 `run_sql` 접근을 제거하고 `semantic_query`만 허용하는 모드 |
44+
| **업무 의미 검토형 질의** | 서버가 질문별 후보를 제한하고, 불확실한 업무 의미는 실행 전에 사람이 확인하며, 모델 대신 서버의 `semantic_query`가 SQL을 만드는 질의 방식 |
4545
| **Fail-closed** | 의미·권한·join·dialect를 확신할 수 없을 때 추측하거나 raw SQL로 우회하지 않고 질문 또는 차단으로 끝내는 동작 |
4646

4747
---
@@ -130,12 +130,12 @@ does not provide a meaningful semantic-query experience.
130130
The bot exits loudly if `DISCORD_BOT_TOKEN` is unset. Full setup and hosting:
131131
[`docs/DEPLOY.md`](docs/DEPLOY.md). Copy [`.env.example`](.env.example) to start.
132132

133-
### 앱에 내장하기: SQL 없는 공개 API
133+
### 앱에 내장하기: 모델이 SQL을 작성하지 않는 공개 API
134134

135135
Discord 외의 앱은 `Lang2SQLRuntime` 공개 API를 사용할 수 있다. 흐름은
136136
`connect → candidates → human feedback → typed plan → execute`다. 호스트와 모델은
137137
SQL 문자열을 만들거나 받지 않으며, 사람의 검토 선택과 서버가 검증한 typed plan만
138-
실행 경계로 넘는다. 현재 governed 실행은 **기존 파일을 read-only로 연 SQLite와
138+
실행 경계로 넘는다. 현재 검토 기반 실행은 **기존 파일을 read-only로 연 SQLite와
139139
DuckDB**에 한정한다. 정확한 DTO, 검토 루프, bound `EQ`/`IN` 필터와 native `DATE`
140140
`[start, end)` 기간창 예제는 [`docs/LIBRARY_API.md`](docs/LIBRARY_API.md)를 따른다.
141141
DB 준비부터 결과 출력까지 한 번에 확인하려면 다음 예제를 실행한다.
@@ -144,18 +144,18 @@ DB 준비부터 결과 출력까지 한 번에 확인하려면 다음 예제를
144144
uv run python examples/semantic_runtime_quickstart.py
145145
```
146146

147-
### Governed semantic mode (semantic first-connect)
147+
### 업무 의미 검토형 질의
148148

149149
`/setup` now performs a PII-safe catalog scan immediately after connecting.
150150
Physical PK/FK facts are accepted automatically, while numeric business metrics
151-
are reviewed only when a real question needs them. In governed mode the model
152-
cannot call `run_sql`; it selects allowlisted IDs, copies the relevant question
153-
phrases, declares the requested aggregate and unresolved obligations, then a
154-
deterministic compiler builds SQL. Phrase-to-column-to-aggregate bindings are
155-
persisted after review, so SUM and AVG over one physical column do not overwrite
156-
each other.
157-
158-
`/setup`이 catalog를 정상 활성화하면 해당 연결은 governed mode로 전환된다.
151+
are reviewed only when a real question needs them. In this reviewed-query mode,
152+
the model cannot call `run_sql`; it selects allowlisted IDs and copies relevant
153+
phrases from the question, declares the requested aggregate and unresolved
154+
obligations, then a deterministic compiler builds SQL.
155+
Phrase-to-column-to-aggregate bindings are persisted after review, so SUM and
156+
AVG over one physical column do not overwrite each other.
157+
158+
`/setup`이 catalog를 정상 활성화하면 해당 연결은 업무 의미 검토형 질의 모드로 전환된다.
159159
이 모드에서는 `run_sql`이 모델 도구 목록에서 제거되고 `semantic_query`만 서버 검증을
160160
거쳐 SQL을 컴파일한다. catalog가 손상되더라도 legacy raw SQL 경로로 되돌아가지 않고
161161
연결을 차단한다.
@@ -173,7 +173,7 @@ dimension phrase when requested → the immutable original question resumes
173173
without a second LLM parse. Destructive or disclosure actions use warning and
174174
confirmation steps; metric/dimension mapping and dimension release bind the confirmation
175175
to the same administrator and exact payload. See
176-
[`docs/SEMANTIC_FIRST_CONNECT.md`](docs/SEMANTIC_FIRST_CONNECT.md) for the exact
176+
[`docs/REVIEWED_SEMANTIC_QUERY.md`](docs/REVIEWED_SEMANTIC_QUERY.md) for the exact
177177
supported scope and fail-closed boundaries.
178178

179179
Guild queries are admin-only by default. Non-admin members can query only in
@@ -191,12 +191,13 @@ suppression rules are not a substitute for database row/column authorization.
191191
- Safety pipeline with the V1 layers (whitelist + timeout), gating every query.
192192
- Legacy raw mode includes `run_sql`, schema exploration/enrichment, semantic
193193
term, ingestion, memory, and clarification tools.
194-
- Governed mode replaces the raw query/exploration surface with
195-
`semantic_query`, blocks sample-based enrichment, and keeps SQL in audit only.
194+
- 업무 의미 검토형 질의 모드는 raw query/exploration surface를
195+
`semantic_query`로 교체하고, sample-based enrichment를 차단하며, SQL은
196+
audit에만 남긴다.
196197
- Memory service (in-memory store + inject-all recall + manual `/remember`).
197198
- Discord frontend (bot, commands, session router, render).
198199
- Encrypted-at-rest secrets (Fernet) and SQLite-backed persistence.
199-
- PII-safe first-connect catalog, lazy metric review, and a typed semantic query
200+
- PII-safe initial catalog, lazy metric review, and a typed semantic query
200201
path for aggregate/group-by queries over declared many-to-one FK paths.
201202
- Private-by-default aggregate disclosure: fewer than five contributing rows
202203
blocks `SUM`/`AVG`/source-record `COUNT`, while `MIN`/`MAX` require an explicit
@@ -219,9 +220,9 @@ suppression rules are not a substitute for database row/column authorization.
219220
match, free search), timestamp/relative/fiscal/cohort time, unit conversion,
220221
derived formulas, composite joins, and fan-out joins fail closed rather than
221222
being guessed or dropped.
222-
- Claim universal dialect parity: current public governed-execution evidence
223+
- Claim universal dialect parity: current public reviewed-execution evidence
223224
covers existing file-backed SQLite and DuckDB only. Connector availability and
224-
verified governed execution are reported separately; unverified remote
225+
verified reviewed execution are reported separately; unverified remote
225226
dialects fail closed.
226227

227228
The cross-domain benchmark currently contains 28 cases over 21 public SQLite

docs/ARCHITECTURE.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
> **두 질의 모드를 구분해서 읽어 주세요.** semantic catalog가 없는 연결은 아래의
66
> legacy `run_sql` 경로를 사용한다. `/setup`으로 catalog가 활성화된 연결은 모델에서
7-
> `run_sql`을 제거하고, [`SEMANTIC_FIRST_CONNECT.md`](./SEMANTIC_FIRST_CONNECT.md)
8-
> governed 경로를 사용한다. 임베딩 애플리케이션은 SQL 없는
7+
> `run_sql`을 제거하고, [`업무 의미 검토형 질의`](./REVIEWED_SEMANTIC_QUERY.md)
8+
> 검토 기반 경로를 사용한다. 임베딩 애플리케이션은 모델이 SQL을 작성하지 않는
99
> [`Lang2SQLRuntime`](./LIBRARY_API.md)을 사용할 수 있다.
1010
1111
---
@@ -46,7 +46,7 @@
4646

4747
핵심 원칙: **로직은 포트(추상)에만 의존, 어댑터(구체)는 가장자리에만**. 그래서 새 LLM·새 DB·새 frontend를 *기존 코드 안 건드리고* 끼울 수 있습니다.
4848

49-
### Governed semantic 질의 경로
49+
### 업무 의미 검토형 질의 경로
5050

5151
```text
5252
Discord 또는 공개 API
@@ -97,7 +97,7 @@ typed blocker로 끝난다.
9797

9898
### `src/lang2sql/semantic/` — 업무 의미, 검토, 계획, 실행 정책 (★④)
9999
- [`catalog.py`](../src/lang2sql/semantic/catalog.py) — 연결별 물리 사실과 검토된 업무 의미
100-
- [`onboarding.py`](../src/lang2sql/semantic/onboarding.py) — PII-safe metadata-only first-connect scan
100+
- [`onboarding.py`](../src/lang2sql/semantic/onboarding.py) — PII-safe metadata-only 초기 연결 scan
101101
- [`shortlist.py`](../src/lang2sql/semantic/shortlist.py) — 질문별 bounded candidate 생성
102102
- [`plan.py`](../src/lang2sql/semantic/plan.py) — SQL 없는 semantic plan IR
103103
- [`compiler.py`](../src/lang2sql/semantic/compiler.py) — 검증된 plan의 결정론적 SQL 컴파일
@@ -125,7 +125,7 @@ typed blocker로 끝난다.
125125
### `src/lang2sql/tools/` — 에이전트가 부르는 capability
126126
대표 도구는 모두 ctx-aware, async다. 연결 모드에 따라 질의 도구가 달라진다.
127127
- [`run_sql.py`](../src/lang2sql/tools/run_sql.py) — catalog가 없는 legacy 연결에서만 safety 통과 후 explorer로 실행
128-
- [`semantic_query.py`](../src/lang2sql/tools/semantic_query.py)governed 연결에서 typed slots만 받고 서버가 SQL을 컴파일
128+
- [`semantic_query.py`](../src/lang2sql/tools/semantic_query.py)업무 의미 검토형 질의 연결에서 typed slots만 받고 서버가 SQL을 컴파일
129129
- [`explore_schema.py`](../src/lang2sql/tools/explore_schema.py) — 테이블/컬럼 introspection
130130
- [`enrich_schema.py`](../src/lang2sql/tools/enrich_schema.py) — LLM으로 컬럼 메타데이터 자동 보강
131131
- [`semantic_federation.py`](../src/lang2sql/tools/semantic_federation.py)`term_custom`: guild/channel/member 계층 용어 사전 (KV 기반, narrow→wide lookup)
@@ -165,7 +165,7 @@ governed dialect는 기존 파일 기반 SQLite와 DuckDB뿐이며, 나머지는
165165

166166
## 4. 한 메시지의 lifecycle (디스코드 멘션 한 번 따라가기)
167167

168-
### Governed mode: catalog가 있는 연결
168+
### 업무 의미 검토형 질의 모드: catalog가 있는 연결
169169

170170
```text
171171
1. 사용자가 자연어 질문을 보낸다.
@@ -178,7 +178,7 @@ governed dialect는 기존 파일 기반 SQLite와 DuckDB뿐이며, 나머지는
178178
8. safety, contributor 보호, 공개 정책, audit와 catalog stamp가 모두 통과해야 결과를 표시한다.
179179
```
180180

181-
정확한 Discord 검토 흐름은 [`SEMANTIC_FIRST_CONNECT.md`](./SEMANTIC_FIRST_CONNECT.md),
181+
정확한 Discord 검토 흐름은 [`REVIEWED_SEMANTIC_QUERY.md`](./REVIEWED_SEMANTIC_QUERY.md),
182182
다른 애플리케이션의 공개 DTO 흐름은 [`LIBRARY_API.md`](./LIBRARY_API.md)를 따른다.
183183

184184
### Legacy mode: catalog가 없는 연결

docs/LIBRARY_API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SQL 없는 임베딩 API
1+
# 모델이 SQL을 작성하지 않는 임베딩 API
22

33
`Lang2SQLRuntime`은 새 애플리케이션이 내부 semantic service나 SQL 객체를 직접
44
다루지 않게 하는 비동기 facade다. 공개 흐름은 다음 다섯 단계다.
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
# Semantic first-connect
1+
# 업무 의미 검토형 질의
22

3-
브랜치는 `semantic-data-context`의 큰 Semantic Pack/Registry/UI를 Lang2SQL에
3+
기능은 `semantic-data-context`의 큰 Semantic Pack/Registry/UI를 Lang2SQL에
44
그대로 복사하지 않는다. 혼탄 시스템에서 유효했던 원칙을 Lang2SQL의 기존 도구
55
경계에 맞춘다.
66

7-
> 모델은 SQL을 쓰지 않고 검토 가능한 typed value만 고른다. SQL은 코드가 만든다.
7+
> 서버는 질문별 후보를 제한하고 모델은 그 후보를 조립한다. 실행에 필요한
8+
> 불확실한 업무 의미는 사람이 확인하며, SQL은 서버 코드가 결정론적으로 만든다.
89
910
## 사용 흐름
1011

@@ -33,13 +34,13 @@
3334
관리자가 다른 사용자의 review를 승인하면 연결만 저장된다. 관리자 채널에서 타
3435
사용자의 DB 결과를 실행하거나 표시하지 않으며, 원 요청자가 다시 질문해야 한다.
3536

36-
## 기존 first-connect와 다른 점
37+
## 기존 초기 연결 방식과 다른 점
3738

38-
| 이전 방식 | 이 브랜치 |
39+
| 이전 방식 | 업무 의미 검토형 질의 |
3940
|---|---|
4041
| 모든 table/column/card 사전 검토 | 물리 catalog 사실은 자동 등록 |
4142
| 작은 DB도 수십 개 업무 결정 | 연결 시 업무 결정 0개; 질문 시 필요한 연결만 검토 |
42-
| `/enrich`가 distinct 샘플을 LLM에 전송 | first-connect는 raw 값을 후보 생성에 사용하지 않음 |
43+
| `/enrich`가 distinct 샘플을 LLM에 전송 | 초기 연결 시 raw 값을 후보 생성에 사용하지 않음 |
4344
| LLM이 `run_sql(sql=...)` 작성 | LLM은 typed ID·질문 표현·집계·미지원 의무만 조립 |
4445
| 전체 pack 승인 후 사용 | 현재 질문 dependency만 확인 |
4546
| 모델 SQL이 join을 자유롭게 선택 | declared FK의 유일한 child-to-parent path만 허용 |
@@ -59,7 +60,7 @@
5960

6061
## 공개 라이브러리 경계
6162

62-
Discord가 아닌 호스트는 SQL 없는 `Lang2SQLRuntime`을 사용한다.
63+
Discord가 아닌 호스트는 모델이 SQL을 작성하지 않는 `Lang2SQLRuntime`을 사용한다.
6364
`connect → candidates → human feedback → typed plan → execute` 순서를 지키며,
6465
호스트/모델은 SQL을 주고받지 않는다. `connect`는 메타데이터만 읽고, `candidates`
6566
질문에 맞춘 bounded ID와 타입만 준다. 사람이 `ReviewRequest.allowed_choices`에서
@@ -69,7 +70,7 @@ Discord가 아닌 호스트는 SQL 없는 `Lang2SQLRuntime`을 사용한다.
6970
typed draft의 predicate는 명시적 AND, exact `EQ` 또는 값 최대 20개의 `IN`
7071
허용하며 모든 값은 bound parameter가 된다. 기간은 native `DATE` 차원의 ISO date
7172
`[start, end)` 창만 받는다. 기존 파일을 read-only로 연 SQLite와 DuckDB만
72-
governed 실행을 지원한다. 상세 DTO와 안전한 검토 루프는
73+
검토 기반 실행을 지원한다. 상세 DTO와 안전한 검토 루프는
7374
[`LIBRARY_API.md`](LIBRARY_API.md)에 있다.
7475

7576
## 안전 경계
@@ -135,7 +136,7 @@ privacy, row-level security 또는 사용자 권한 보장이 아니다.
135136
- 모든 테이블의 명시적 physical source-record `COUNT(*)` (PK 불필요)
136137
- categorical dimension group-by
137138
- declared FK를 따라가는 유일한 child → parent 1~N hop join
138-
- 기존 file-backed SQLite와 DuckDB의 read-only governed 실행과 결과 비교
139+
- 기존 file-backed SQLite와 DuckDB의 read-only 검토 기반 실행과 결과 비교
139140
- metadata-only 문자열 공개 후보 및 수치 지표 후보
140141
- 모든 비차단 dimension의 metadata-only phrase mapping과 conflict 검증
141142
- 질문 시점의 metric/dimension review와 immutable draft 재개

docs/USAGE.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Lang2SQL Discord 사용 가이드
22

3-
governed semantic mode에서 LLM은 SQL을 직접 쓰지 않는다. LLM은 질문을 서버가 검증할
3+
업무 의미 검토형 질의 모드에서 LLM은 SQL을 직접 쓰지 않는다. LLM은 질문을 서버가 검증할
44
수 있는 지표·집계·분류 슬롯으로 조립하고, 서버가 확인된 값만으로 read-only SQL을
55
만든다.
66

@@ -55,7 +55,7 @@ credential-bearing DSN을 채널 명령으로 직접 받는 `/connect`는 노출
5555

5656
`/setup`이 catalog를 활성화한 뒤에는 같은 연결에서 다음 경계가 적용된다.
5757

58-
| 기능 | Catalog 없는 legacy mode | Catalog 있는 governed mode |
58+
| 기능 | Catalog 없는 legacy mode | Catalog 있는 업무 의미 검토형 질의 모드 |
5959
|---|---|---|
6060
| 자연어 질의 도구 | 모델이 `run_sql`을 호출 | 모델은 `semantic_query`의 typed slot만 조립 |
6161
| SQL 작성 | 모델이 SQL 문자열 작성 | 서버 compiler만 검증된 SQL 작성 |
@@ -212,10 +212,11 @@ DuckDB에 한정된다. 다른 DB 커넥터는 연결 가능성과 timeout/취
212212
| contributor·disclosure 차단 | 결과가 너무 작거나 차원이 아직 공개되지 않음 | 데이터 공개 정책을 확인하고, 허용되는 경우에만 관리자 검토 |
213213
| catalog/audit 오류 | 의미 변경이나 실행을 안전하게 기록할 수 없음 | 저장소 오류를 복구한 뒤 새 plan으로 다시 시도 |
214214

215-
차단 사유를 무시하고 `run_sql`로 우회하는 것은 governed mode의 복구 방법이 아니다.
215+
차단 사유를 무시하고 `run_sql`로 우회하는 것은 업무 의미 검토형 질의 모드의 복구
216+
방법이 아니다.
216217

217218
## 기타 기존 명령
218219

219220
`/ingest`, `/confirm_ingest`, `/term_custom`, `/remember`, `/audit_me`는 기존
220-
기능으로 남아 있다. `/enrich``/org_setup`의 raw-value sampling은 semantic
221-
first-connect가 활성화된 DB에서는 의도적으로 비활성화된다.
221+
기능으로 남아 있다. `/enrich``/org_setup`의 raw-value sampling은 업무 의미
222+
검토형 질의가 활성화된 DB에서는 의도적으로 비활성화된다.

docs/discord_first_redesign_v4_1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> **역사적 설계 문서**: 아래 명령 표는 2026-05 계획 당시의 walking skeleton이다.
44
> 현재 실행 표면은 [`USAGE.md`](./USAGE.md)
5-
> [`SEMANTIC_FIRST_CONNECT.md`](./SEMANTIC_FIRST_CONNECT.md)를 따른다. 현재
5+
> [`REVIEWED_SEMANTIC_QUERY.md`](./REVIEWED_SEMANTIC_QUERY.md)를 따른다. 현재
66
> Discord에는 raw DSN `/connect`가 없고 `/setup`을 사용한다.
77
88
> **작성일**: 2026-05-18

examples/semantic_runtime_quickstart.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Run a fully local, SQL-free Lang2SQLRuntime aggregate example.
1+
"""Run a local aggregate query using bounded semantic IDs and explicit review.
22
33
Run from an installed package, or from this repository with:
44
uv run python examples/semantic_runtime_quickstart.py

src/lang2sql/adapters/llm/openai_.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,7 @@ def _decode_completion(raw: dict[str, Any]) -> Completion:
154154
args = (
155155
decoded_args
156156
if isinstance(decoded_args, dict)
157-
else {
158-
"__invalid_argument_shape__": type(decoded_args).__name__
159-
}
157+
else {"__invalid_argument_shape__": type(decoded_args).__name__}
160158
)
161159
tool_calls.append(
162160
ToolCall(id=tc.get("id", ""), name=fn.get("name", ""), arguments=args)

0 commit comments

Comments
 (0)