5단계 — clone 직후 자동 완성
5. 검증 IDE 체계 — clone 직후 자동완성 (5a 구현 완료)
현재 구조
clone 직후 자동완성을 차단하는 요인은 세 겹입니다.
Validation.csproj가 gitignore 대상입니다 — clone에 프로젝트 파일이 없습니다.- 참조가 머신 종속입니다 — HintPath는
typeof(Context).Assembly.Location, 즉 그 실행이 돌았던 위치의 기록입니다(RuleScaffold.cs:131). 규칙 API가 도구 본체tabbit.dll안에 있어 참조가 설치 위치에 결속됩니다. 단일 파일 배포본에서는Location이 빈 문자열이라<Reference>블록 자체가 생략됩니다. Tables.자동완성의 원천인.generated/도 gitignore 대상입니다.
5a. 규칙 API의 계약 어셈블리 분리
| 비교 | (가) 계약 어셈블리 물리 분리 | (나) 본체의 참조 어셈블리 동봉 |
|---|---|---|
| 방법 | Context·SchemaView·FileMap·SqlStore·RedisStore 표면을 별도 프로젝트로. 본체가 프로젝트 참조 | 본체 빌드의 ProduceReferenceAssembly 산출물을 내장 후 실행 시 기록 |
| API 계약 | 명시됩니다 — 규칙 작성자 표면이 어셈블리 경계 | 본체 public 전체가 그대로 노출(현행과 동일) |
| 구조 변경 | 중규모 — Context 구현이 본체 내부(셀 역참조·모델)와 결합되어 있어 구현 주입으로 역전 필요 | 코드 변경 최소 |
| 빌드 복잡성 | 없음 | 2단계 빌드 — 자기 ref asm을 자기 리소스로 넣는 순환을 빌드 스크립트로 풀어야 합니다 |
(가)로 확정합니다. 규칙 작성자에게 계약을 주는 것이 피드백의 취지와 일치하고, 빌드 체계를 건드리지 않으며, 4단계의 임베드 대상에 이 dll이 합류합니다. 타입 동일성은 본체가 같은 어셈블리를 참조하므로 자동으로 성립합니다.
5a-1. 의존 실측 (2026-08-14) — src/Validation 11파일 2,962줄 전수
판정: 중간 규모 리팩터링. 설계 변경은 아닙니다.
공개 시그니처는 이미 거의 닫혀 있습니다. Context의 public 멤버 22개와 협력 타입 6개(공개
멤버 60개)의 시그니처에 나타나는 본체 타입은 Newtonsoft.Json.Linq.JToken 하나뿐입니다.
Model · Table · Field · Location · Diagnostics · Severity · TabbitException ·
RuleFile · CellLocator · RuleScope는 단 한 곳도 공개 시그니처에 나타나지 않습니다 —
전부 private 필드·private 메서드·internal 생성자에만 있습니다. 무엇을 계약으로 할지는 이미
정해져 있고, 정할 것이 남아 있지 않습니다.
이 상태가 우연이 아니라는 근거가 둘 있습니다. TargetSide는 모델의 enum이 아니라
.ToString()을 거친 string으로 노출되고(SchemaView.cs:79,145), 행을 짚는 보고는 생성
레코드를 object로 받아 CellLocator가 리플렉션으로 역산합니다(Context.cs:167,
CellLocator.cs:78-96). 둘 다 모델 타입이 규칙 표면에 새지 않게 미리 막아 둔 자리입니다.
리팩터링인 이유는 구현이 그 타입들 안에 들어 있기 때문입니다. 7개 공개 타입이 전부
sealed class + internal ctor로 본체 타입을 생성자에서 직접 받습니다 —
SchemaView(Model) · TableSchema(Table) · FieldSchema(TableSchema, Field) ·
Context(RuleScope). 계약으로 옮기려면 「인터페이스(계약) + 구현(본체)」로 쪼개야 하고, 그러지
않으면 계약이 Model · Diagnostics · MySqlConnector · Npgsql · StackExchange.Redis를 전부
끌고 갑니다.
| 타입 | 파일 | 공개 시그니처가 끌고 오는 것 | 옮길 수 있나 |
|---|---|---|---|
Context (22 멤버) | Context.cs:115-352 | JToken · 나머지는 계약 내부 타입과 BCL | 인터페이스화 필요. 시그니처는 무손실 |
SchemaView · TableSchema · FieldSchema | SchemaView.cs:24-164 | 계약 내부 타입뿐 | 가능 |
FileMap | ExternalFiles.cs:22-64 | 없음 | 결합 제로. 그대로 옮길 수 있습니다 |
SqlStore · RedisStore | RuntimeStores.cs:21-187 | 없음 — BCL 컬렉션만 반환 | 인터페이스로만. 클래스째 옮기면 계약이 DB 드라이버 2개를 참조합니다 |
RuleStage · RulePriorityAttribute | RuleFolders.cs:15-28 · RulePriorityAttribute.cs | 없음 | 순수. 규칙 작성자가 직접 쓰므로 계약에 필수 |
규모. 계약으로 옮길 것이 7타입 약 633줄(인터페이스와 POCO만 두면 250~300줄), 본체에 남을 것이 약 2,190줄입니다.
5a-3. 구현 (2026-08-14)
인터페이스만 옮겼습니다. 그 결정 하나가 실측이 꼽은 어려운 지점 둘을 없앴습니다 — 구현
클래스가 전부 제자리에 남으므로 AssetRoots가 FileMap의 internal 생성자를 부르는 것이
그대로이고, DB 드라이버 3종과 TabbitException은 계약에 나타나지 않습니다.
| 무엇 | 어디 |
|---|---|
| 계약 어셈블리 | src/Contract/ — 어셈블리 이름 Tabbit.Validation, 네임스페이스도 Tabbit.Validation 그대로 |
| 계약의 내용 | IContext · ISchemaView · ITableSchema · IFieldSchema · IFileMap · ISqlStore · IRedisStore + RuleStage + RulePriorityAttribute — 이후 IContext가 단계별 넷으로 갈렸습니다(IPreContext · IGlobalContext · ITableContext · IRuntimeContext, 파이프라인 스펙의 「단계마다 다른 컨텍스트」) |
| 계약의 의존 | Newtonsoft.Json 하나. 로깅도, 모델도, 드라이버도 없습니다 |
| 호스트 쪽 | 기존 클래스가 인터페이스를 구현합니다. 계약 타입을 돌려주는 8개 멤버만 명시적 구현이 필요했습니다 |
Context | internal sealed class RuleContext : IContext가 되었습니다 |