Files
DongHyeonkaandClaude Opus 5 ab59130196 chore: 이전 세션이 남긴 변경을 커밋한다
이번 파이프라인 작업과 무관하게 작업 트리에 남아 있던 것을 그대로 올린다.
사용자가 「전부 커밋」으로 정했고, 이번 작업과 섞이지 않게 커밋만 나눴다.

대부분은 clean-architecture-backend-template 의 그림 정본 재배치다 —
final/assets/diagrams/<이름>/ 에 있던 것이 CLAUDE.md 가 적은 배치인
final/assets/<이름>/ 로 옮겨졌고 .techviz/<이름>/ 이 함께 들어왔다.
삽입 줄의 대부분(3.15M)이 그 .techviz context.json 이다.

그 밖에 ca-tmpl·document-haness 의 정리, .claude/agents/ 열한 개,
writing-practitioner-guides 스킬, .playwright-mcp 세션 산출물,
scripts/check-ssot-facts.py 와 그 시험이 들어 있다.

이 커밋의 내용은 내가 만든 것이 아니라 이전 세션이 남긴 것이고 검증하지 않았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:02:02 +09:00

7.2 KiB

tech-log-tree.json 예시

구조 예시다. 실제 분석을 수행해 만든 결과가 아니므로 이 값을 그대로 옮겨 쓰지 않는다. 실제 프로젝트에서는 같은 모양에 진짜 source anchor 와 evidence 를 채우고 readiness 를 판정한다.

트리는 이 파일 하나다. 사람이 읽는 트리와 Node Specification 을 따로 쓰고 대조하던 절차는 없다 — 계약과 색인이 같은 파일이라 어긋날 자리가 없다.

{
  "schemaVersion": 4,
  "project": "n+1liner",
  "ssot": "final/document.md",
  "ssotSha256": "<sha256>",
  "sourceRevision": "<git-revision>",
  "generatedAt": "<YYYY-MM-DD>",
  "candidateScope": {
    "document": "final/document.md",
    "sections": ["§3", "§4", "§5", "§6", "§7", "§8", "§9", "§10", "§11"],
    "excluded": ["제2부 — 모듈 분석 전문", "제3부 — 분석 재료"]
  },
  "contract": {
    "readinessValues": ["READY", "OPEN", "NEEDS_EVIDENCE", "NEEDS_DECISION", "BLOCKED"],
    "dispositionValues": {
      "PROMOTE": "독립 Tech Log 로 쓴다",
      "MERGE_INTO": "다른 기록의 한 절로 흡수한다",
      "KEEP_IN_SSOT": "분석에는 남기고 독립 기록으로 만들지 않는다",
      "NEEDS_EVIDENCE": "주장에 아직 검증이 없다",
      "NEEDS_DECISION": "방향이 그럴듯하지만 프로젝트가 정하지 않았다",
      "BLOCKED": "원본이 불완전하거나 서로 어긋난다"
    }
  },
  "topics": {
    "jpa-feed-query-performance": {
      "topic": "jpa-feed-query-performance",
      "title": "JPA 피드 조회 성능",
      "readerQuestion": "피드 한 화면을 그리는 데 쿼리가 몇 번 나가고, 조회 전략을 바꿀 때 무엇이 함께 바뀌는가?",
      "kinds": {
        "case": [
          {
            "title": "필드 접근 없이 발생한 EAGER ToOne N+1",
            "kind": "case",
            "slug": "eager-to-one-n-plus-one",
            "readiness": "READY",
            "source": ["final/document.md#user-page-연관-숨은-추가-쿼리-정량화"],
            "code": ["FeedQueryRepository.java:loadFeed"],
            "evidence": ["evidence/raw/explain/highlights-child-plan-A.txt"],
            "classification": "조회 한 번에 나간 쿼리 수를 세어 재현했고 실행계획으로 확인했다",
            "missing-verification": "동시 트래픽에서는 재지 않았다",
            "relations": ["reference:fetch-type-vs-fetch-strategy"]
          }
        ],
        "concept": [
          {
            "title": "Fetch Type 과 Fetch Strategy 가 갈라지는 자리",
            "kind": "concept",
            "slug": "fetch-type-and-fetch-strategy",
            "readiness": "READY",
            "source": ["final/document.md#fetch-type과-fetch-strategy"],
            "basis-version": "Hibernate 6.4 · Spring Data JPA 3.2",
            "classification": "이 구분을 먼저 알아야 위 Case 의 관측을 읽을 수 있다",
            "relations": ["case:eager-to-one-n-plus-one"]
          }
        ],
        "reference": [
          {
            "title": "Fetch Type 과 Fetch Strategy 를 구분한다",
            "kind": "reference",
            "slug": "fetch-type-vs-fetch-strategy",
            "readiness": "READY",
            "source": ["final/document.md#fetch-type과-fetch-strategy"],
            "classification": "다음 프로젝트에도 적용할 조회 기준이다",
            "scope": "JPA 연관을 하나라도 조회하는 모듈",
            "exceptions": "단건 조회만 있는 경로에는 걸리지 않는다",
            "relations": ["case:eager-to-one-n-plus-one"]
          }
        ],
        "question": [
          {
            "title": "ANALYZE 이후 Cardinality Estimate 는 어떻게 달라지는가",
            "kind": "question",
            "slug": "cardinality-estimate-after-analyze",
            "readiness": "OPEN",
            "source": ["final/document.md#query-plan-측정"],
            "known": "현재 통계에서 Plan B 의 추정 행 수는 실제의 1/8 이다",
            "unknown": "통계를 갱신하면 플래너가 같은 계획을 고르는지",
            "next-verification": "seed(1000) 뒤 ANALYZE highlights 를 돌리고 Plan B 를 다시 잰다",
            "decision-criterion": "추정치가 실제의 2배 안이면 닫고, 벗어나면 통계 갱신 주기를 정하는 Decision 으로 넘긴다",
            "relations": ["case:eager-to-one-n-plus-one"]
          }
        ],
        "decision": [
          {
            "title": "Collection Fetch Join 과 Pagination 을 같이 쓰지 않는다",
            "kind": "decision",
            "slug": "no-collection-fetch-join-with-pagination",
            "readiness": "READY",
            "decision-status": "ADOPTED",
            "source": ["final/document.md#컬렉션-fetch-join-페이징"],
            "decision-evidence": ["case:eager-to-one-n-plus-one"],
            "grounds": "메모리 페이징으로 떨어지는 것을 실행계획에서 확인했다",
            "classification": "대안을 두고 프로젝트가 실제로 고른 방향이다",
            "relations": ["case:eager-to-one-n-plus-one"]
          }
        ],
        "setup": []
      }
    }
  },
  "candidates": [
    {
      "id": "F012",
      "kindCandidate": "CASE",
      "sourceRefs": ["final/document.md#user-page-연관-숨은-추가-쿼리-정량화"],
      "summary": "필드 접근 없이 EAGER ToOne 이 추가 쿼리를 냈다",
      "disposition": "PROMOTE",
      "dispositionReview": "CONFIRMED",
      "target": "case:eager-to-one-n-plus-one",
      "reason": "재현·진단·결론이 한 사건 안에서 닫힌다"
    },
    {
      "id": "F013",
      "kindCandidate": "CASE",
      "sourceRefs": ["final/document.md#컬렉션-n1-정량화"],
      "summary": "같은 원인으로 컬렉션 쪽에서도 추가 쿼리가 났다",
      "disposition": "MERGE_INTO",
      "dispositionReview": "CONFIRMED",
      "target": "case:eager-to-one-n-plus-one",
      "reason": "같은 결함의 두 번째 증상이다. 그 Case 의 표에 행으로 들어간다"
    },
    {
      "id": "F014",
      "kindCandidate": "CONCEPT",
      "sourceRefs": ["final/document.md#분석-범위"],
      "summary": "이번 분석에서 읽은 리포지터리 메서드는 41개다",
      "disposition": "KEEP_IN_SSOT",
      "dispositionReview": "CONFIRMED",
      "target": null,
      "reason": "분석 범위 계수다. 분석에는 남아야 하고 공개 기록으로는 읽을 사람이 없다"
    }
  ],
  "counts": { "topics": 1, "nodes": 5, "written": 0, "unwritten": 5, "unlisted": 0, "candidates": 3 },
  "unlisted": [],
  "history": {}
}

이 예시가 보여 주는 것

  • 후보 셋 중 하나만 글감이 됐다. MERGE_INTOKEEP_IN_SSOT 이 없는 분해는 선별하지 않은 분해다.
  • Concept 은 Case 를 먼저 고른 뒤에 그것을 읽는 데 필요해서 더했다.
  • Question 에 decision-criterion 이 있다. 무엇이 나오면 닫는지를 적지 않으면 검증을 마쳐도 열려 있다.
  • 여섯 종류를 억지로 채우지 않아도 된다. 여기서 다섯이 다 있는 까닭은 실제로 다섯이 있었기 때문이고, 여섯 번째인 setup 은 비어 있다 — 이 프로젝트에는 남이 따라 할 절차가 없었다.