/longinusKG-Code traceability — KG↔Code 관통 바인딩.
/longinus Claude Code CLI 또는 연결된 에이전트에서 호출합니다.
> **롱기누스의 창이 관절을 관통하듯, KG의 의미 계층 사이사이를 소스코드 참조로 꿰뚫는다.** > Span → Twin → Contract → SourceCode — 어느 층에서 시작하든 코드까지, 코드에서 어느 층까지든 추적 가능. ---
APT의 ST(SemanticTwin)는 **의미**를 결정화하고, SCW(SourceCodeWorld)는 **코드**를 물질화한다. 그런데 이 둘 사이에 **참조가 없으면** AI는 맥락을 잃는다: - "이 Contract가 어떤 코드로 구현됐지?" → 모름 - "이 함수가 어떤 Contract에서 나왔지?" → 모름 - "Contract 변경 시 어떤 파일을 수정해야 하지?" → 추측만 가능 롱기누스 방법론은 이 **단절을 관통**한다. KG 노드마다 두 가지 ref를 꽂아넣어서 **semantic ↔ implementation** 양방향 추적을 보장한다. ---
모든 SCW 결과물에 두 가지 ref를 부여한다:
| Ref | 설명 | 예시 |
|-----|------|------|
| **`sourceId`** | 코드 내용의 식별자 — 함수명, 클래스명, 모듈 식별자 | `LoginService.authenticate` |
| **`sourcePath`** | 코드의 물리적 위치 — file:line | `src/auth/login.ts:42` |
```
KG Layer: [Span] → [Twin] → [Contract] → [SourceCodeNode]
↓
Longinus Ref: sourceId: "LoginService.authenticate"
sourcePath: "src/auth/login.ts:42"
↓
Physical Layer: 실제 파일의 실제 라인
```
--- SCW에서 `ContractMaterialized` 후, 또는 기존 코드를 KG에 역매핑할 때 실행. ```cypher // 아직 롱기누스 ref가 없는 SourceCodeNode 찾기 MATCH (ct:AptContract)-[:MATERIALIZES]->(src:SourceCodeNode) WHERE src.sourceId IS NULL OR src.sourcePath IS NULL RETURN ct.name AS contract, src.file_path AS file, ct.status ``` ---
코드의 **의미적 식별자**를 결정한다. 함수/클래스/모듈 수준에서 가장 구체적인 이름. **규칙:** - 함수 단위 구현 → `ModuleName.functionName` (예: `AuthService.login`) - 클래스 단위 구현 → `ClassName` (예: `UserProfileValidator`) - 모듈 전체 → `module_name` (예: `auth_middleware`) - 중첩 → dot notation (예: `OrderProcessor.Validator.check`) **금지:** - 파일명 그대로 쓰기 (`login.ts` ← 이건 sourcePath 역할) - 추상적 이름 (`handler`, `processor`, `service` 단독) ---
코드의 **물리적 위치**. `file_path:start_line` 형식.
**규칙:**
- 프로젝트 루트 기준 상대경로 사용
- 라인 번호는 함수/클래스 **선언 시작 라인**
- 범위가 넓으면 `file_path:start-end` (예: `src/auth/login.ts:42-87`)
```bash
# sourcePath 자동 추출 예시
grep -n "def authenticate\|function authenticate\|authenticate(" src/auth/login.ts
# → src/auth/login.ts:42
```
--- ```cypher
// SourceCodeNode에 이중 ref 설정
MATCH (ct:AptContract {name: $contract_name})-[:MATERIALIZES]->(src:SourceCodeNode)
SET src.sourceId = $sourceId, // e.g. "LoginService.authenticate"
src.sourcePath = $sourcePath, // e.g. "src/auth/login.ts:42"
src.pierced_at = datetime() // 관통 시점
RETURN ct.name, src.sourceId, src.sourcePath
```
**역방향 — 코드에도 KG ref 주석 삽입** (SCW의 FulfillmentGate Check #5와 연동):
```python
# KG: CT_Project_Auth | ST_Project_Auth | TASK_Project_Auth
# LONGINUS: sourceId=AuthService.login, sourcePath=src/auth/login.py:15
def login(email: str, password: str) -> AuthResult:
...
```
--- Span부터 SourceCode까지 **전체 체인이 끊김 없이 관통**되었는지 검증.
```cypher
// 관통 완성도 체크 — 끊어진 체인 탐지
MATCH (atom:AtomicSpan)-[:CRYSTALLIZES_TO]->(twin:SemanticTwin)
MATCH (twin)-[:HAS_CONTRACT]->(ct:AptContract)
OPTIONAL MATCH (ct)-[:MATERIALIZES]->(src:SourceCodeNode)
WITH atom.name AS span, twin.name AS twin, ct.name AS contract,
src.sourceId AS sourceId, src.sourcePath AS sourcePath,
CASE
WHEN src IS NULL THEN 'NO_SOURCE'
WHEN src.sourceId IS NULL THEN 'NO_ID'
WHEN src.sourcePath IS NULL THEN 'NO_PATH'
ELSE 'PIERCED'
END AS status
RETURN span, twin, contract, sourceId, sourcePath, status
ORDER BY status DESC
```
**관통 상태 분류:**
| Status | 의미 | 조치 |
|--------|------|------|
| `PIERCED` | 완전 관통 — 양쪽 ref 모두 존재 | 정상 |
| `NO_PATH` | sourceId는 있으나 위치 미지정 | sourcePath 코드가 변경되면 sourcePath의 라인 번호가 밀린다. 주기적으로 검증.
```bash
# sourcePath 유효성 검증 — 해당 라인에 sourceId가 실제로 존재하는지
grep -n "$sourceId" "$sourcePath_file" | head -1
# 결과가 sourcePath_line과 다르면 → drift 발생
```
```cypher
// Drift 플래그 설정
MATCH (src:SourceCodeNode {name: $src_name})
WHERE src.sourcePath IS NOT NULL
SET src.drift_detected = true,
src.drift_at = datetime(),
src.old_sourcePath = src.sourcePath
// 이후 새 위치로 sourcePath 업데이트
```
**Drift 해소:**
1. `grep -rn` 으로 sourceId의 현재 위치 탐색
2. sourcePath 업데이트
3. `drift_detected = false` 리셋
--- 새 프로젝트가 아닌, **기존 코드베이스를 KG에 매핑**할 때의 절차.
```
1. 프로젝트 소스 파일 스캔
2. 함수/클래스 단위로 sourceId 후보 추출
3. 각 후보에 대해:
a. KG에 SourceCodeNode MERGE
b. sourceId, sourcePath 설정
c. 대응되는 Contract가 있으면 MATERIALIZES 연결
d. Contract가 없으면 → 역으로 Contract 초안 생성 (ST로 에스컬레이션)
```
```cypher
// 역매핑: 코드에서 KG로
MERGE (src:SourceCodeNode {file_path: $file_path})
SET src.sourceId = $sourceId,
src.sourcePath = $sourcePath,
src.pierced_at = datetime(),
src.reverse_mapped = true // 역매핑임을 표시
// Contract 연결 (있으면)
WITH src
OPTIONAL MATCH (ct:AptContract {target_file: $file_path})
FOREACH (_ IN CASE WHEN ct IS NOT NULL THEN [1] ELSE [] END |
MERGE (ct)-[:MATERIALIZES]->(src)
)
RETURN src.sourceId, src.sourcePath, ct.name AS linked_contract
```
--- ```cypher
// 프로젝트별 관통률
MATCH (ct:AptContract)
OPTIONAL MATCH (ct)-[:MATERIALIZES]->(src:SourceCodeNode)
WITH ct.name AS contract,
CASE WHEN src.sourceId IS NOT NULL AND src.sourcePath IS NOT NULL
THEN 1 ELSE 0 END AS pierced
RETURN count(*) AS total_contracts,
sum(pierced) AS pierced_count,
toFloat(sum(pierced)) / count(*) * 100 AS pierce_rate_pct
```
--- | 금지 | 이유 | 대안 | |------|------|------| | sourceId에 파일명 사용 | sourcePath와 역할 중복 | 함수/클래스 의미명 사용 | | sourcePath 없이 sourceId만 | 절반 관통 = 추적 불가 | 반드시 이중 ref | | 라인 번호 생략 | 파일만으로는 대형 파일에서 위치 특정 불가 | `file:line` 필수 | | drift 무시 | 코드 변경 후 KG가 거짓말 | 주기적 drift 검증 | | 코드 주석 없이 KG만 업데이트 | 양방향이어야 함 | `# LONGINUS:` 주석도 삽입 | | Contract 없이 관통 | 의미 없는 ref | ST 완료 후 관통 | ---
롱기누스 작업 후 `apt-progress.md`에 기록: ```markdown ### Longinus Piercing Progress - [x] CT_Project_Auth → AuthService.login (src/auth/login.py:15) PIERCED - [x] CT_Project_Profile → UserProfile.update (src/user/profile.py:33) PIERCED - [ ] CT_Project_Search → (SCW 미완료, NO_SOURCE) - Pierce Rate: 66% (2/3) ``` --- *롱기누스의 창은 한 번 꽂으면 뽑히지 않는다. KG와 코드 사이의 참조도 마찬가지다.*