전체 문서
이 페이지 목차
PostgreSQL table-level constraint matrix
PostgreSQL table-level constraint matrix · 관계
이 대상이 사용하는 구현·계약·의존 · 17개
- 계약 사용 · company_scope · fresh table-level constraint contract for `company_scope` · db-table-constraints
- 계약 사용 · exploration_nodes · fresh table-level constraint contract for `exploration_nodes` · db-table-constraints
- 계약 사용 · exploration_edges · fresh table-level constraint contract for `exploration_edges` · db-table-constraints
- 계약 사용 · exploration_anchors · fresh table-level constraint contract for `exploration_anchors` · db-table-constraints
- 계약 사용 · main_sessions · fresh table-level constraint contract for `main_sessions` · db-table-constraints
- 계약 사용 · task_relations · fresh table-level constraint contract for `task_relations` · db-table-constraints
- 계약 사용 · task_asset_links · fresh table-level constraint contract for `task_asset_links` · db-table-constraints
- 계약 사용 · task_llm_profiles · fresh table-level constraint contract for `task_llm_profiles` · db-table-constraints
- 계약 사용 · agents · fresh table-level constraint contract for `agents` · db-table-constraints
- 계약 사용 · agent_prompts · fresh table-level constraint contract for `agent_prompts` · db-table-constraints
- 계약 사용 · agent_prompt_vars · fresh table-level constraint contract for `agent_prompt_vars` · db-table-constraints
- 계약 사용 · mcp_tools_cache · fresh table-level constraint contract for `mcp_tools_cache` · db-table-constraints
- 계약 사용 · agent_visibility · fresh table-level constraint contract for `agent_visibility` · db-table-constraints
- 계약 사용 · agent_skill_visibility · fresh table-level constraint contract for `agent_skill_visibility` · db-table-constraints
- 계약 사용 · finding_traffic_bindings · fresh table-level constraint contract for `finding_traffic_bindings` · db-table-constraints
- 계약 사용 · side_question_sessions · fresh table-level constraint contract for `side_question_sessions` · db-table-constraints
- 계약 사용 · side_question_requests · fresh table-level constraint contract for `side_question_requests` · db-table-constraints
db/schema.sql의 fresh CREATE TABLE 블록에 있는 table-level clause 24개를 17개 table에서 전수 분리한다. Column-level PK/UNIQUE/FK/CHECK와 startup ALTER 제약은 이 분모 밖이며, 설치된 DB를 실행 관찰한 결과가 아니다. DDL 근거
판독 규칙
- Composite column은 DDL 순서를 그대로 쓴다. PK/UNIQUE는 PostgreSQL unique index를 만들므로 동시 충돌을 직렬화하지만, 애플리케이션이
ON CONFLICT를 쓰는지는 production access matrix에서 별도로 본다. - PostgreSQL UNIQUE는 기본적으로 null끼리를 같은 값으로 보지 않는다. Nullable key를 포함한
company_scope두 제약은 null row 전체를 하나로 제한하지 않는다. ON DELETE는 table-level clause가 아니라 관련 column FK의 효과를 함께 적었다. Composite invariant가 FK 대상 소속 일치까지 보장한다고 확대 해석하지 않는다.- Fresh 제약과 legacy migration 결과가 다른 경우는 migration 경계가 권위다.
24/24 matrix
| table / clause | 정확한 column 순서·식 | 보장하는 invariant | delete·동시성·남는 경계 |
|---|---|---|---|
company_scope uq_sv2_domain |
UNIQUE (company_id, domain) |
같은 company의 동일 non-null domain 중복 금지 | company delete는 row CASCADE; null domain은 여러 row 가능; 동시 insert는 unique index에서 충돌 |
company_scope uq_sv2_net |
UNIQUE (company_id, net) |
같은 company의 동일 non-null CIDR 중복 금지 | company delete CASCADE; null net은 여러 row 가능 |
company_scope ck_company_scope_payload |
kind별 (domain, net, value) XOR: domain은 domain만, ip/cidr은 net만, icp/keyword는 value만 non-null |
kind와 payload column 조합 일치 | raw/reason 내용과 canonicalization은 보장하지 않음; startup이 drop/add하며 legacy row 전수 재검증 |
exploration_nodes ck_node_kind |
kind IN (begin,goal,intent,fact,finding,hint,digest) |
node kind allowlist | exploration delete CASCADE; conditional legacy replacement의 탐지 한계는 migration 참조 |
exploration_nodes ck_node_state |
kind별 state 조합 | 예: intent만 running/paused/done/blocked/exhausted/stopped/deleted, digest만 active/superseded | 상태 전이 순서 자체는 보장하지 않음; legacy row가 새 식을 위반하면 replacement 실패 |
exploration_edges primary key |
(exploration_id, src_id, rel, dst_id) |
같은 exploration 안 동일 방향·relation edge 중복 금지 | exploration/src/dst delete CASCADE; src/dst가 같은 exploration 소속인지는 FK만으로 보장하지 않음 |
exploration_edges ck_edge_noself |
src_id <> dst_id |
동일 node self edge 금지 | 반대 방향 cycle과 장거리 cycle은 허용 |
exploration_edges ck_edge_rel |
rel IN (spawns,derived_from,yields,proves,covers) |
relation allowlist | 동적 legacy replacement가 여러 old check 중 하나만 drop할 수 있음 |
exploration_anchors primary key |
(node_id, asset_id) |
동일 node↔asset anchor 중복 금지 | node/asset delete 모두 CASCADE; node와 asset의 task/exploration 소속 일치는 별도 코드 책임 |
main_sessions primary key |
(exploration_id, seq) |
exploration별 segment sequence 중복 금지 | exploration delete CASCADE; seq >= 1이라는 설명은 DB CHECK로 보장하지 않음 |
task_relations primary key |
(task_id, source_task_id) |
동일 direct inheritance edge 중복 금지 | 양쪽 task delete CASCADE; relation은 direct이며 재귀/cycle 금지는 보장하지 않음 |
task_relations ck_task_relation_not_self |
task_id <> source_task_id |
직접 self relation 금지 | 두 task 이상의 cycle은 허용 |
task_asset_links primary key |
(task_id, asset_id) |
task↔asset provenance row 하나 | task/asset delete CASCADE, source node delete SET NULL; competing insert는 PK 충돌/ON CONFLICT 경로로 조율 |
task_llm_profiles primary key |
(task_id, profile_id) |
같은 profile을 task chain에 두 번 넣지 않음 | task/profile delete CASCADE |
task_llm_profiles unique |
(task_id, position) |
task chain에서 position 하나당 row 하나 | 서로 다른 task는 같은 position 가능; 위치 연속성은 보장하지 않음 |
agents agents_role_ck |
role IN (goals,main,planner,worker,assistant) |
agent role allowlist | agent delete의 prompt/visibility 효과는 각 FK를 따름; trigger mode fresh/upgrade CHECK 차이는 별도 |
agent_prompts unique |
(agent_id, version) |
agent별 prompt version 중복 금지 | agent delete CASCADE; agents.current_prompt_id는 후속 FK로 SET NULL |
agent_prompt_vars unique |
(agent_id, var_name) |
agent별 variable 이름 중복 금지 | agent delete CASCADE |
mcp_tools_cache unique |
(server_id, tool_name) |
MCP server별 discovered tool 이름 중복 금지 | server delete CASCADE; discovery refresh의 최신성은 보장하지 않음 |
agent_visibility primary key |
(agent_id, resource_kind, resource_id, mcp_tool_name) |
agent별 MCP resource/tool visibility row 중복 금지 | agent delete CASCADE; resource_id에는 FK가 없어 target 삭제 무결성을 DB가 보장하지 않음 |
agent_skill_visibility primary key |
(agent_id, skill_name) |
agent별 Skill visibility row 중복 금지 | agent delete CASCADE; filesystem Skill 존재는 DB가 보장하지 않음 |
finding_traffic_bindings unique |
(finding_id, snapshot_id) |
같은 finding에 같은 snapshot 중복 binding 금지 | finding delete CASCADE; snapshot delete는 기본 NO ACTION이라 참조 중 삭제를 거부 |
side_question_sessions check |
(conversation_id non-null AND task/exploration/intent null) OR (conversation_id null AND task/exploration non-null) |
standalone conversation와 task/exploration parent 형식을 배타적으로 선택 | intent는 task branch에서 optional이며 해당 exploration 소속임을 보장하지 않음; 참조 대상 delete는 CASCADE |
side_question_requests unique |
(session_key, generation, client_id) |
한 session generation에서 client request idempotency key 중복 금지 | session delete CASCADE; running 1개 제한은 별도 partial unique index가 담당 |
의미 판정
| 분모 | C | A/U |
|---|---|---|
| fresh CREATE table-level clause | 24/24 | 0 |
| invariant·composite 순서·FK delete 해석 | 24/24 정적 해석 | runtime isolation, 실제 충돌 결과와 installed drift는 U |
| legacy와 동일한 설치 결과 | — | trigger mode/task action divergence, conditional replacement, repeated validation 때문에 A/U |