Files
document-haness/docs/clean-architecture-backend-template/final/evidence/meta/a05-f014-collection-fetch-pagination-probe.json
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

15 lines
5.2 KiB
JSON

{
"assetKey": "a05-f014-collection-fetch-pagination-probe",
"kind": "terminal",
"command": "mkdir -p /tmp/probe\ncat > /tmp/probe/cp.sh <<'CPSH'\n# 락파일의 한 구성에 실린 좌표 전부를 캐시 경로로 바꾼다. Gradle 실행 없이 재현된다.\nLOCK=${1:-adapter/outbound/persistence-jpa/gradle.lockfile}\nCONF=${2:-postgresqlIntegrationTestRuntimeClasspath}\nCACHE=/root/.gradle/caches/modules-2/files-2.1\ncp=\"\"\nwhile IFS= read -r line; do\n coord=${line%%=*}; confs=${line#*=}\n case \",$confs,\" in *\",$CONF,\"*) ;; *) continue ;; esac\n group=${coord%%:*}; rest=${coord#*:}; name=${rest%%:*}; ver=${rest##*:}\n jar=$(find \"$CACHE/$group/$name/$ver\" -name '*.jar' ! -name '*sources*' ! -name '*javadoc*' 2>/dev/null | head -1)\n [ -n \"$jar\" ] && cp=\"$cp:$jar\"\ndone < <(grep -E '^[a-zA-Z0-9._-]+:[^=]+=' \"$LOCK\")\necho \"${cp#:}\"\nCPSH\ncd src\nCP=$(bash /tmp/probe/cp.sh)\necho '# 락파일이 고정한 제공자'\necho \"$CP\" | tr : '\\n' | grep -E 'hibernate-core|/h2-' | sed 's|.*/||'\necho -n '# 저장소에서 fail_on_pagination_over_collection_fetch 를 켜는 곳: '\ngrep -rn 'fail_on_pagination' --include=*.java --include=*.yml --include=*.yaml --include=*.properties --include=*.gradle --exclude-dir=build .. | wc -l\n\necho\necho '# 게이트와 같은 모양의 조회를 그 제공자에게 직접 시킨다'\ncat > /tmp/probe/FetchPageProbe.java <<'JAVA'\nimport jakarta.persistence.CascadeType;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.GenerationType;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.ManyToOne;\nimport jakarta.persistence.OneToMany;\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.cfg.Configuration;\n\n/** 컬렉션 페치에 페이지 상한을 걸었을 때 상한이 SQL 로 가는지 본다. */\npublic class FetchPageProbe {\n\n @Entity(name = \"PagedParent\")\n public static class Parent {\n @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) Long id;\n String label;\n @OneToMany(mappedBy = \"parent\", cascade = CascadeType.ALL) List<Child> children = new ArrayList<>();\n }\n\n @Entity(name = \"PagedChild\")\n public static class Child {\n @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) Long id;\n String label;\n @ManyToOne Parent parent;\n }\n\n public static void main(String[] args) {\n Configuration cfg = new Configuration();\n cfg.setProperty(\"hibernate.connection.driver_class\", \"org.h2.Driver\");\n cfg.setProperty(\"hibernate.connection.url\", \"jdbc:h2:mem:fetch;DB_CLOSE_DELAY=-1\");\n cfg.setProperty(\"hibernate.connection.username\", \"sa\");\n cfg.setProperty(\"hibernate.hbm2ddl.auto\", \"create-drop\");\n cfg.setProperty(\"hibernate.generate_statistics\", \"true\");\n cfg.addAnnotatedClass(Parent.class);\n cfg.addAnnotatedClass(Child.class);\n\n try (SessionFactory factory = cfg.buildSessionFactory()) {\n factory.inTransaction(session -> {\n for (int p = 0; p < 50; p++) {\n Parent parent = new Parent();\n parent.label = \"parent-\" + p;\n for (int c = 0; c < 4; c++) {\n Child child = new Child();\n child.label = \"child-\" + p + '-' + c;\n child.parent = parent;\n parent.children.add(child);\n }\n session.persist(parent);\n }\n });\n\n long before = factory.getStatistics().getPrepareStatementCount();\n List<Parent> page = factory.fromTransaction(session ->\n session.createQuery(\n \"select distinct p from PagedParent p left join fetch p.children order by p.id\",\n Parent.class)\n .setMaxResults(20)\n .getResultList());\n long statements = factory.getStatistics().getPrepareStatementCount() - before;\n\n System.out.println(\"반환된 부모 수 : \" + page.size());\n System.out.println(\"그 조회가 낸 프리페어드 스테이트먼트 : \" + statements);\n System.out.println(\"fail_on_pagination_over_collection_fetch : \"\n + factory.getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled());\n }\n }\n}\nJAVA\njavac -encoding UTF-8 -nowarn -cp \"$CP\" -d /tmp/probe /tmp/probe/FetchPageProbe.java 2>&1 | grep -v '^Note:'\njava -Dstdout.encoding=UTF-8 -cp \"$CP:/tmp/probe\" FetchPageProbe 2>&1 \\\n | grep -E 'HHH90003004|반환된|스테이트먼트|fail_on' | sed 's/^[0-9:.]* \\[main\\] //'\n\necho\necho '# 서버 없이 매 빌드마다 도는 레인에도 같은 형태가 있다'\nsed -n '11,19p' adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/testkit/fetch/FetchPaginationExpectationTest.java",
"cwd": "/shared/codebase/clean-architecture-backend-template",
"exitCode": 0,
"executedAt": "2026-09-02T04:06:14+00:00",
"sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916",
"raw": "evidence/raw/a05-f014-collection-fetch-pagination-probe.txt",
"svg": "evidence/rendered/a05-f014-collection-fetch-pagination-probe.svg",
"rawSha256": "91a21e235440739eb729b0da52a4bac4a742c691b207551b59f36ec425a0a517",
"lines": 21,
"redaction": "none — 코드베이스 정적 검색"
}