Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-24 13:03 UTC

bssm-oss / nova-reactive

reactive JPA - nova-reactive 동기 JPA처럼 사용하기 쉬운 비동기 JPA 라이브러리 입니다.

JavaApache-2.0★ 4 estrellas⑂ 0 forksdesde may 2026Ver en GitHub ↗

bssm-oss/nova-reactive tiene un índice de salud de 56 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (77/100) y la más baja, Community & Adoption (40/100). Se actualizó por última vez hace 4 días. Una sola persona concentra la mayor parte del trabajo reciente.

56
global / 100
Moderado

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

56
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

Titularidad

BSSM-OSSOrganización
20 seguidores98 repositorios públicosdesde mar 2026

Este repositorio está respaldado por una organización: una custodia compartida y responsable que puede sobrevivir a cualquier mantenedor individual.

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

77Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 4 días
7.6/36Cadencia de commits — 11/52 semanas con commits
18/18Volumen de commits — 246 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year246
human_commit_share1
days_since_last_push4
active_weeks_last_year11
Cómo se puntúa
27/27Publica versiones — 18 versiones publicadas
36/36Recencia de las versiones — última versión hace 4 días
27/27Cadencia de publicación — una versión cada ~0,3 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count18
latest_release_tagv2.10.0
releases_from_tagsno
days_since_latest_release4
mean_days_between_releases0,3
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

40En riesgo · 18% del índice global
Cómo se puntúa
7.7/60Estrellas — 4 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars4
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (Apache-2.0)
18/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
6.3/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
has_contributing
has_issue_templateno
has_code_of_conductno
has_pull_request_template

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

51Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 5 contributing companies or organizations
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
46.8/46.8Resolución de issues — 100% de issues cerradas
38.2/38.3Aceptación de PR — 56/56 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs56
open_issues0
closed_issues6
issue_closed_ratio1
closed_unmerged_prs0
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
9.5/25Alcance del propietario — 20 seguidores de bssm-oss
13.7/25Trayectoria — 98 repos públicos, cuenta de ~0 años
Datos de entrada utilizados
followers20
owner_typeOrganization
is_verified
owner_loginbssm-oss
public_repos98
account_age_days130

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

62Moderado · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 2 flujo(s) de trabajo
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
6.4/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — 0 out of 25 merged PRs checked by a CI test -- score normalized to 0
Datos de entrada utilizados
has_ci
has_tests
has_editorconfig
has_linter_configno
has_precommit_configno
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
10/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dir
has_description

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

46En riesgo · 16% del índice global
Cómo se puntúa
6/7.5Binary-Artifacts — binaries present in source code
0/7.5Branch-Protection — sin datos
0/2.5CI-Tests — 0 out of 25 merged PRs checked by a CI test -- score normalized to 0
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 5 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
7.5/7.5Token-Permissions — GitHub workflow tokens follow principle of least privilege
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate4,6
Excluidos de la puntuación (sin datos o no aplicable): branch_protection, signed_releases. Los pesos restantes se han renormalizado.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

65Moderado · 0% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — AGENTS.md, CLAUDE.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 100 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes5527
Cómo se puntúa
12.6/18Arranque con un solo comando — benchmark/build.gradle.kts, build.gradle.kts, nova-project/nova-cache/build.gradle.kts (convención del toolchain, sin ejecutor de tareas)
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — Java (tipado estático)
0/10Entorno reproducible
0/10Práctica demostrada con agentes — ningún commit con autoría de agente entre los últimos 100
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfiles
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0
toolchain_manifestsbenchmark/build.gradle.kts, build.gradle.kts, nova-project/nova-cache/build.gradle.kts, nova-project/nova-core/build.gradle.kts, nova-project/nova-dialects/nova-dialect-h2/build.gradle.kts, nova-project/nova-dialects/nova-dialect-mariadb/build.gradle.kts, nova-project/nova-dialects/nova-dialect-mysql/build.gradle.kts, nova-project/nova-dialects/nova-dialect-oracle/build.gradle.kts, nova-project/nova-dialects/nova-dialect-postgresql/build.gradle.kts, nova-project/nova-example/build.gradle.kts, nova-project/nova-metamodel/build.gradle.kts, nova-project/nova-metrics-micrometer/build.gradle.kts, nova-project/nova-r2dbc/build.gradle.kts, nova-project/nova-spring-boot-starter/build.gradle.kts, nova-project/nova-spring-data/build.gradle.kts, nova-project/nova/build.gradle.kts
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — Java (tipado estático)
54.1/55Tamaños de archivo manejables — 8/483 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageJava
largest_source_bytes296.519
source_files_sampled483
oversized_source_files8
Cómo se puntúa
0/40Esquema de API (OpenAPI/GraphQL/proto)
0/20Servidor MCP
40/40Ejemplos ejecutables — example
Datos de entrada utilizados
example_dirsexample
has_mcp_signalno
api_schema_files

Datos clave

4estrellas de GitHub
1contribuidores
246commits en los últimos 12 meses
4días desde el último push
18versiones publicadas
1factor bus
0issues abiertas
Mavenecosistemas de paquetes

Advertencias de recopilación de datos

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 4.6 / 10
4.6agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).Scorecard v5.5.0 · 2026-07-24 13:03 UTC

8Binary-Artifactsbinaries present in source code
n/dBranch-Protectioninternal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
0CI-Tests0 out of 25 merged PRs checked by a CI test -- score normalized to 0
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
10Contributorsproject has 5 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
10Token-PermissionsGitHub workflow tokens follow principle of least privilege
10Vulnerabilities0 existing vulnerabilities detected
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 2348,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Java": 3821975,
        "Shell": 616
      },
      "pushed_at": "2026-07-20T08:42:49Z",
      "created_at": "2026-05-14T02:07:53Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-17T15:14:41Z",
      "description": "reactive JPA - nova-reactive 동기 JPA처럼 사용하기 쉬운 비동기 JPA 라이브러리 입니다.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Java",
      "significant_languages": [
        "Java"
      ]
    },
    "owner": {
      "blog": null,
      "name": "BSSM-OSS",
      "type": "Organization",
      "login": "bssm-oss",
      "company": null,
      "location": null,
      "followers": 20,
      "avatar_url": "https://avatars.githubusercontent.com/u/268493872?v=4",
      "created_at": "2026-03-16T02:53:46Z",
      "is_verified": null,
      "public_repos": 98,
      "account_age_days": 130
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v2.10.0",
          "kind": "minor",
          "published_at": "2026-07-20T08:48:20Z"
        },
        {
          "tag": "v2.9.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:42Z"
        },
        {
          "tag": "v2.8.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:41Z"
        },
        {
          "tag": "v2.7.1",
          "kind": "patch",
          "published_at": "2026-07-17T13:46:39Z"
        },
        {
          "tag": "v2.7.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:38Z"
        },
        {
          "tag": "v2.6.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:36Z"
        },
        {
          "tag": "v2.5.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:34Z"
        },
        {
          "tag": "v2.4.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:33Z"
        },
        {
          "tag": "v2.3.1",
          "kind": "patch",
          "published_at": "2026-07-17T13:46:31Z"
        },
        {
          "tag": "v2.3.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:30Z"
        },
        {
          "tag": "v2.2.1",
          "kind": "patch",
          "published_at": "2026-07-17T13:46:28Z"
        },
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:26Z"
        },
        {
          "tag": "v2.1.2",
          "kind": "patch",
          "published_at": "2026-07-17T13:46:25Z"
        },
        {
          "tag": "v2.1.1",
          "kind": "patch",
          "published_at": "2026-07-17T13:46:23Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:46:22Z"
        },
        {
          "tag": "v2.0.0",
          "kind": "major",
          "published_at": "2026-06-12T01:45:55Z"
        },
        {
          "tag": "v1.0.1",
          "kind": "patch",
          "published_at": "2026-06-01T07:21:03Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-06-01T06:24:11Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "205ff7ae934d89b9a879f7241b940a5d30725319",
          "body": "Bare @Name in a title (e.g. OneToMany, Id, Entity) links to real GitHub\naccounts/orgs and notifies unrelated people. Require writing annotations without\n@ or in backticks. Release notes are escaped by release-drafter; titles are not.",
          "is_bot": false,
          "headline": "docs: forbid bare annotation @-mentions in commit/PR titles (#62)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-17T15:13:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6170d2a4f4141f18f21957521bb71c94f4b8b6bf",
          "body": "…(#61)\n\nrelease.yml only published to Maven Central — nothing ever published a GitHub\nRelease, so v2.1.0..v2.9.0 shipped to Central while the Releases page stopped at\nv2.0.0 and release-drafter's draft sat unpublished. Add a github-release job that\npublishes that draft once Central succeeds.\n\nreleas\n[…]\nPR\ntitles (@Id, @Entity, @OneToMany, ...) rendered as mentions of real accounts and\nnotified unrelated people. Escape '@' at the source; $AUTHOR is templated\nseparately so author credit is unaffected.",
          "is_bot": false,
          "headline": "ci: publish GitHub Release on tag push and stop annotation @mentions …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-17T14:42:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "91d0bd1bcf3182b043266205b5d3eb2d04d6d624",
          "body": "…ation to parallel-cycle (#58)\n\nPhase 2: architect surfaces open product/scope decisions as questions;\norchestrator confirms via deep-interview before spawning implementers.\nPhase 3: author != reviewer separation — independent test author,\nsecurity-reviewer lane for SQL-generating tracks, dedicated verifier,\nand reviewer receives approved design + user decisions as oracle.",
          "is_bot": false,
          "headline": "docs(skills): add design deep-interview gate + multi-agent role separ…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-17T14:41:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "41e5db30f3d1b129c88c55e76b8e335d8ac8e1e5",
          "body": "* feat(core): @OneToMany session diff-at-flush (S1)\n\nBring cascade-persist/orphanRemoval @OneToMany collections into the\ntransaction-bound persistence session's diff-at-flush pipeline instead\nof eagerly cascading at save time. Loaded children are registered into\nthe session identity map so their own\n[…]\n excludeIds parameter (empty for the\nstateless eager-cascade caller, which has no session/reparenting\nconcept); disownOrphans's signature is unchanged — its callers simply\npass a pre-filtered id list.",
          "is_bot": false,
          "headline": "feat(core): @OneToMany session diff-at-flush (collection epic S1) (#60)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T07:29:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "552c720e13398c3f2f1b7374fcd76a34605a01ad",
          "body": "…functions, TRIM/EXTRACT (#59)\n\n* feat(query): JPQL expression parity — quantified subqueries, JPA 3.1 functions, TRIM/EXTRACT syntax\n\n- ANY/ALL/SOME quantified subquery comparison (SOME normalized to ANY),\n  rendered as portable '<op> any (subquery)' / '<op> all (subquery)'.\n- Extend scalar functio\n[…]\nvering ANY/ALL/SOME, EXTRACT, TRIM\n  forms, LEFT/RIGHT vs LEFT JOIN, LOCAL temporal, and KEY/VALUE/ENTRY/\n  INDEX rejection; updates its LOCAL TIME/DATETIME assertion to match\n  the corrected mapping.",
          "is_bot": false,
          "headline": "feat(query): JPQL expression parity — quantified subqueries, JPA 3.1 …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T06:47:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4113cb78c1a7bb35c177c2875c8ed19a19b6d4a2",
          "body": "…ge-safety checklist into parallel-cycle (#57)\n\n- nova-release: tag→GH Actions→Maven Central 발행 절차 + 3대 함정(OSSRH≠Portal\n  transfer, PGP 미발행 400, gpg 차단 curl 우회) + 보안 hard rule.\n- jpa-parity-feature: fail-fast→실지원 전환→잔여 fail-fast→H2 통합→문서 5단계 템플릿.\n- parallel-cycle Phase 5: 흩어진 머지-안전 로어(stale-base cherry-pick, merge-tree\n  예측, trailing-param 손실, grep -a, cwd/absolute-path, 전체 build semantic 검증)를\n  6항목 체크리스트로 명시화.",
          "is_bot": false,
          "headline": "chore(skills): add nova-release + jpa-parity-feature skills, fold mer…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T02:58:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e5de1c56082d8cc99c64e67cb0f532f9d095d739",
          "body": "…unts, Pageable/Page/Slice returns (#56)\n\n* feat(spring-data): extend derived query keywords — findTop<N>By/findFirst<N>By counts, IgnoreCase\n\nAdds two previously unsupported derived-query-method keywords to the\nSpring Data derived query parser/dispatcher:\n\n- findTop<N>By / findFirst<N>By with an ex\n[…]\ndow / Mono<Page> /\nMono<Slice>). Drop the stale 'IgnoreCase / dynamic Pageable not supported'\nlimitation line and call out the parse-time fail-fast for Pageable on a\nnon-paging return type or subject.",
          "is_bot": false,
          "headline": "feat(spring-data): derived-query parity — IgnoreCase, findTop<N>By co…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T02:45:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b05023adb6737d0fb9bba03fe7e5d880ba72cbe6",
          "body": "…tion/GROUP BY/ORDER BY, JOINED/TPC TREAT, entity @MapKeyClass (#55)\n\n* feat(core): support composite-key to-one in JPQL GROUP BY/ORDER BY\n\nrenderGroupByBody/renderOrderByBody now detect a terminal composite-key\nto-one path via the existing compositeToOneRef/appendCompositeColumn\nhelpers and expand \n[…]\nE_PER_CLASS (polymorphic derived table)\n- @MapKeyClass single-@Id entity key now supported (composite-@Id still fail-fast)\nRemaining fail-fast narrowed accordingly (LIKE, entity-returning JPQL WHERE).",
          "is_bot": false,
          "headline": "feat(core): JPA fail-fast edges round 2 — composite-key to-one projec…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T02:38:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8a8c8dd3f53dd7da1e4354ea036adf819db2846d",
          "body": "…ry module errors (#54)\n\n* fix(docs): correct broken transaction-definition example and missing modules\n\n- transactions.md showed operations.inTransaction(TransactionDefinition, tx -> ...)\n  as if it were a ReactiveEntityOperations overload; that method does not exist —\n  ReactiveEntityOperations.in\n[…]\n back.\n\nNo behavior changes; only message strings. Existing message-substring\nassertions (\"does not extend\", \"FOR SHARE\", \"Unsupported repository\nmethod\") are preserved so no test updates were needed.",
          "is_bot": false,
          "headline": "docs + error-message UX: fix inaccurate doc examples, clarify non-que…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T02:21:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "87d27da74baaf722ea32d2daaca9f4e61c379b73",
          "body": "…Call, MariaDB SEQUENCE, Oracle DDL leaks (#53)\n\n* fix(postgresql): render stored-procedure calls as select * from proc(...)\n\nPostgreSQL's CALL statement only works against CREATE PROCEDURE objects,\nbut Nova's ReactiveStoredProcedureQuery is an IN-only + result-set model\n(OUT/INOUT/REF_CURSOR fail f\n[…]\n Oracle's `ALTER TABLE ... ADD (...)` form.\n\nAdds cross-surface rendering regression tests covering the generator table,\nidempotent link/collection/secondary/JOINED DDL, and ddl-auto column additions.",
          "is_bot": false,
          "headline": "fix(dialects): cross-dialect type-token/DDL audit — PostgreSQL render…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T02:18:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a3c78deb1f1674d327cf4a0c8ac17dca62985b5",
          "body": "…ery counter (#52)\n\nAdds MicrometerSqlOperationMetricsListener, which subscribes to the existing\ncore SqlExecutionListener hooks (no core changes) and publishes metrics not\nyet exposed by MicrometerSqlExecutionListener:\n\n- nova.sql.operation.duration: Timer tagged by operation\n  (save/find/delete/qu\n[…]\nstener)\n\nSqlOperationClassifier approximates the operation from the SQL statement's\nleading keyword since SqlExecutionListener does not carry which\nReactiveEntityOperations method triggered execution.",
          "is_bot": false,
          "headline": "feat(metrics-micrometer): add per-operation latency timer and slow-qu…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T02:13:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4408d4e7ab8370a28d0ca4d0e56ab9b6c744d3b5",
          "body": "…ning, concurrent-track cap) (#51)",
          "is_bot": false,
          "headline": "chore(skill): document multi-track concurrency (hub-disjoint partitio…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T01:48:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3e81eaf58dac7c57932d3507b38aeef23a30c3cf",
          "body": "…red review, streaming merge, dedicated E2E agent (#50)",
          "is_bot": false,
          "headline": "chore(skill): update parallel-cycle pipeline — design-first, risk-tie…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T01:24:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e3f246924039c2871783605daa0a2aa93a6cc4b5",
          "body": null,
          "is_bot": false,
          "headline": "docs: bump documented coordinates to 2.8.0 (#49)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T01:09:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "233acf9c719c734de9f8b4a39331955c4ae16865",
          "body": "…o-one WHERE ops, nested EntityGraph leaf, @MapKeyClass @Embeddable, @AssociationOverride on @MappedSuperclass (#48)\n\n* feat(core): composite-key to-one in ordering/BETWEEN/IN query positions\n\nExtend composite-key (@EmbeddedId/@IdClass) to-one association support from\njoin + equality/IS NULL to orde\n[…]\nved out of Not-yet-supported.\n- Narrowed remaining fail-fast: composite-key to-one projection/LIKE and\n  entity-returning JPQL WHERE; deeper subgraph under a composite leaf; entity\n  @MapKeyClass key.",
          "is_bot": false,
          "headline": "feat(core): implement remaining JPA fail-fast edges — composite-key t…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-15T01:05:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "afdb31542b4ca1ed184bf25dc3e6033f19e32c0a",
          "body": "… doc correction, broken query examples, clearer fail-fast messages (#47)\n\n* fix(core) + docs: JPA parity honesty pass — honor @Basic(optional), correct cascade docs, fix broken query examples\n\n- @Basic(optional=false) now enforced as NOT NULL (was fully ignored); combines\n  with @Column(nullable) a\n[…]\n-returning JPQL unsupported message drops the internal 'Wave2 W1'\n  codename and the stale 'wait for the Criteria API' (Criteria API already ships);\n  it now points users to the Criteria API directly.",
          "is_bot": false,
          "headline": "fix(core) + docs: JPA parity honesty pass — @Basic(optional), cascade…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-14T23:59:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "edf284ff9354eaf02e83ea17146ac9a86e1da33e",
          "body": "…DDL fix, cross-dialect rendering coverage, JPA compatibility matrix (#46)\n\n* docs: add JPA compatibility matrix and refresh version/roadmap\n\nAdd docs/jpa-compatibility.md — a reactive jakarta.persistence feature matrix\n(supported / reactive-equivalent / fail-fast) covering the 2.0.0–2.7.0 parity\nwo\n[…]\ny uniqueness gate\n- Fix misleading CriteriaEntityTranslator message: composite to-one LIKE/BETWEEN/IN now reports the accurate unsupported reason instead of pointing at a non-existent aliased SQL path",
          "is_bot": false,
          "headline": "fix(oracle) + test + docs: stabilization pass — Oracle composite-key …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-14T06:44:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b51412c0977eec9c90e237faa4ddba842c0b9d6b",
          "body": "…to-one auto-hydration, @ManyToMany (#45)\n\n* feat(core): multi-column ON for Criteria/JPQL joins over composite-key to-one targets\n\nReplace the WA fail-fast guards that rejected composite-key\n(@EmbeddedId/@IdClass) to-one join/terminal paths with real multi-column\nforeign-key rendering. Join ON cond\n[…]\nata test for @JoinColumn referencedColumnName alignment\n  (declaration order reversed vs referenced @Id order) and an H2 batch-hydration\n  test for two composite owners sharing a leading id component.",
          "is_bot": false,
          "headline": "feat(core): composite-key relations end-to-end — multi-column joins, …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-14T05:40:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9d204b6f3f74afd88f95e893663c93ade56aa45b",
          "body": "…onent derivation, @Access(PROPERTY) for to-one relations (#44)\n\n* feat(core): support nested EntityGraph subgraph fetch (depth>1)\n\nResolve @NamedSubgraph / EntityGraph.addSubgraph into a recursive FetchNode\ntree and hydrate each level with a batch IN-query, instead of fail-fast on\ndepth>1. Preserve\n[…]\n single scalar owner component is\nambiguous and previously threw a cryptic runtime error. Reject cleanly at metadata\nbuild via a new declaresCompositeId helper. Single-@Id target derivation unchanged.",
          "is_bot": false,
          "headline": "feat(core): nested EntityGraph subgraph fetch, @MapsId composite-comp…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-14T04:43:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fe95b783543e47c335a64cd102abf83ede14dcb0",
          "body": "…anyToOne/@OneToOne relation target via multi-column FK (#43)\n\n* feat(core): support @ManyToOne / owning @OneToOne referencing composite-key (@EmbeddedId/@IdClass) targets\n\nModel to-one relationships whose target uses a composite key as an ordered\nN-column foreign key instead of the previous single-\n[…]\nriteria\n  terminal-reference rejections, and @SqlResultSetMapping + named-query mapper\n  rejections (previously only stored-proc). Existing composite round-trip and\n  single-key regression stay green.",
          "is_bot": false,
          "headline": "feat(core): support composite-key (@EmbeddedId/@IdClass) entity as @M…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-14T03:26:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e2cc4e34493e6bc0de4208960b561418c3a1258f",
          "body": "…@StoredProcedureQuery, @AssociationOverride, @MapKey temporal/class, inherited-@Id FK (#42)\n\n* feat(core): reactive @StoredProcedureQuery / @NamedStoredProcedureQuery (W7)\n\nAdd a reactive equivalent of JPA stored procedure queries as a new isolated\nsubsystem under io.nova.query.storedprocedure.\n\n- \n[…]\nkey path unchanged.\n\nRegression test drives the version guard through @OneToMany(orphanRemoval) with\ntwo sibling rows sharing the first id component; reverting to first-component\nbinding makes it red.",
          "is_bot": false,
          "headline": "feat: JPA parity batch 3 — composite-key delete/locking, TREAT/TYPE, …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-14T01:46:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a6a6e7a1dc75b97184f1443a82b2918ac9328b4",
          "body": "…keys) (#41)\n\n* fix(core): align to-one FK column type with referenced @Id storage type\n\n@ManyToOne / owning @OneToOne FK properties hardcoded javaType to Long, so\nthe FK DDL was always bigint and FK values were bound as raw bigint. When the\nreferenced entity's @Id was not Long (UUID/String/Integer/\n[…]\nred rather than shipped untested.\n\n- Added Short-target H2 round-trip (previously unit-only) alongside the\n  existing UUID/String/Integer/Long round-trips.\n\nLong path untouched. ./gradlew build green.",
          "is_bot": false,
          "headline": "fix(core): align to-one FK column type with referenced @Id (non-Long …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-13T23:22:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "72c43766408102c474bc7793f7dc11b8efd45106",
          "body": "…anager locking, native result mapping, query cache (#40)\n\n* feat(cache): wire second-level query result cache + SharedCacheMode policy\n\nAdd opt-in query result caching to the nova-cache decorator, isolated to\nthe cache module (no core/r2dbc/dialect edits).\n\n- ReactiveQueryCache SPI reworked to be e\n[…]\nation); query cache read-through hit and write\ninvalidation with JPQL/Criteria read surfaces staying consistent; and a UUID @Id\nentity persisted via EntityManager visible to JPQL and the entity cache.",
          "is_bot": false,
          "headline": "feat: JPA parity batch 2 — scalar types, JPQL/Criteria joins, EntityM…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-13T10:09:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f5cfc645c9f175654016d501d57929ce6725fc37",
          "body": "…ment types (#39)\n\n* feat(core): support enum, UUID, and more basic @ElementCollection element types\n\nBasic @ElementCollection only fully supported a narrow set of element types.\n@Enumerated enum elements threw at schema generation (elementColumnType had\nno enum branch), and Set<UUID> stored fine bu\n[…]\node to exclude valueConverter so equal mappings with\n  distinct converter instances compare equal.\n\n./gradlew :nova-project:nova-core:test :nova-project:nova-r2dbc:test and\n./gradlew build both green.",
          "is_bot": false,
          "headline": "feat(core): support enum, UUID, and more basic @ElementCollection ele…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-13T07:17:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "101a105b938a2d3761b073967a310cf33116c788",
          "body": "…tityGraph, 2nd-level cache, @Query (#38)\n\n* feat(core): minimal add/remove diff for session collection flush (Stage 2-4)\n\nSession-managed owning @ManyToMany and basic @ElementCollection collections\nnow flush as a minimal diff against the persisted baseline instead of a full\ndelete-and-reinsert: onl\n[…]\nriteria results served from the\nsecond-level cache, standard Pageable paging, no-N+1 graph loading, and a\nregression that em.flush() over the cache decorator pushes the session UPDATE\nmid-transaction.",
          "is_bot": false,
          "headline": "feat: reactive JPA feature parity — EntityManager, JPQL, Criteria, En…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-07-13T06:32:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5633315eb02f1f23031f3c516dc948a8173130cb",
          "body": "… issues\n\nRemediation is no longer a single pass: after each fix the change must be\nre-reviewed (and E2E re-run) and the loop continues until no critical/major\nremain. \"No issues\" may only be declared when unresolved critical/major is zero;\ndesign-blocked majors are explicitly backlogged and reported to avoid infinite loops.",
          "is_bot": false,
          "headline": "docs(skill): make review/E2E remediation a converging loop until zero…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-30T09:23:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "feaa88b555b3225678616dea74dc44df185e8183",
          "body": "…+ PR flow\n\nNew order: scope split → parallel team work → parallel review (pre-merge) →\nremediation → merge to integration branch → E2E (full build + run nova-example) →\nremediation → PR create & squash-merge → next-cycle confirm. Reviews now happen on\nworktree branches before main is touched; the cycle merges into cycle/<topic> and\nships via a squash-merged PR instead of committing to local main directly.",
          "is_bot": false,
          "headline": "docs(skill): restructure parallel-cycle to review-before-merge + E2E …",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-30T03:08:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4a4546ac868c9dd1934759fe574d4cee3bf2ad78",
          "body": "…ion (Stage 1)\n\nWithin a persistence session (inTransaction), owning @ManyToMany and\n@ElementCollection table writes are no longer issued immediately on save — they are\ndeferred to flush, where each collection's current state is compared against a\nbaseline captured on load and synchronized only when\n[…]\naptures baselines after hydration.\n\nTest: SessionCollectionFlushIntegrationTest — unchanged collection emits no link\nSQL; a dirty collection mutated without an explicit save is synchronized at commit.",
          "is_bot": false,
          "headline": "feat(core): defer session collection sync to flush with change detect…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T05:42:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "52734cadfc2625f71c2bb000dd1477542fae5366",
          "body": "runInNewTransaction committed via flatMap(result -> commit...), which never runs\non an empty source — so an inTransaction whose callback completes without emitting\n(side-effect-only work such as a session flush, or a body ending in .then()) closed\nthe connection without committing, silently discardi\n[…]\ncompletion (value path still commits via\nflatMap; errors still roll back). Surfaced by session collection flush, whose\ndeferred writes happen at commit time even when the transaction returns no value.",
          "is_bot": false,
          "headline": "fix(r2dbc): commit transactions that complete without a value",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T05:42:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fee09c936d2b2803f215095b5ffb843a476e1a8d",
          "body": "…aths; guard version\n\nFollow-up to the cascade review of 0071f83/fdf31b2.\n\nMajor 1 — owned-collection cleanup was wired only into delete(entity), so\ndeleteById, deleteAll(Iterable), deleteAllById and the cascade-remove path (which\nroutes through deleteById) still left @ElementCollection / owning @Ma\n[…]\nanup, stale-version preserves owned-collection rows,\n@ManyToMany cascade self-referential cycle termination, cascade=MERGE re-saves\nmodified existing targets, tightened no-cascade rejection assertion.",
          "is_bot": false,
          "headline": "fix(core): extend owned-collection delete cleanup to all per-entity p…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T04:56:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fdf31b226e4419c82f4f1849bc4a220ca2fe406d",
          "body": "…side\n\nPreviously any @ManyToMany(cascade=...) was rejected. Owning-side cascade is now\nhonored: on owner save, PERSIST cascades transient targets (persisted before the\nlink rows are written) and MERGE re-saves already-persisted targets too. Cascade\ndeclared on the inverse (mappedBy) side is still r\n[…]\nget still\nerrors with a message pointing at cascade=PERSIST.\n\nTests: factory honor (owning ALL) + reject (inverse cascade); H2 round-trip\ncascade-persist of transient targets and no-cascade rejection.",
          "is_bot": false,
          "headline": "feat(core): support @ManyToMany(cascade=PERSIST/MERGE) on the owning …",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T04:39:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0071f83b0ea1b7bf9e7b3ffa0eec45209ef2ae8c",
          "body": "Deleting an owner left its @ElementCollection collection-table rows and its\nowning @ManyToMany join-table link rows behind — reconcile (which clears them)\nonly runs on save, never on delete. With @ForeignKey now emitting FK constraints\nfrom those tables to the owner, the orphaned rows also make the \n[…]\nllow-up).\n\nAlso collapses a duplicated ensurePrimaryVersionPresent javadoc block.\n\nTest: OwnerDeleteCollectionCleanupIntegrationTest (element-collection + M2M link\ncleanup, target preservation) on H2.",
          "is_bot": false,
          "headline": "fix(core): clean up owned collection rows on owner hard delete",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T04:32:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c4c6dfaf576770e9484e7aa1546bb17155be8baf",
          "body": "… limits\n\nFrom hardening review (no code defects found):\n- ensurePrimaryVersionPresent: note that \"lock failure ⇒ no change\" atomicity for\n  a versioned @SecondaryTable hard delete holds only inside a transaction — the\n  COUNT / secondary DELETE / primary DELETE sequence has a narrow TOCTOU window\n \n[…]\nthat identifier-length bounding applies only to the\n  auto-generated name; an explicit @ForeignKey(name=...) is the caller's\n  responsibility and may exceed dialect limits (idempotency is unaffected).",
          "is_bot": false,
          "headline": "docs(core): document transaction-scope atomicity and FK name bounding…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T03:21:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "48ea063aef0f5ae4acffbeb736c533af210d9f05",
          "body": "…to=UPDATE\n\naddOneToManyOrderColumns issued an unconditional ALTER TABLE ADD COLUMN for the\norder column, ignoring SchemaOptions. On a second create() with ifNotExists=true\n(the ddl-auto=UPDATE restart path) this failed with \"duplicate column\" and broke\ncontext startup — the same non-idempotency cla\n[…]\n Dialect#listColumnsSql and order columns\nthat already exist are skipped; fresh create/recreate still emit unconditionally.\n\nTest: OneToManyOrderColumnIntegrationTest repeated-create idempotency (H2).",
          "is_bot": false,
          "headline": "fix(core): make @OneToMany @OrderColumn ALTER idempotent under ddl-au…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T03:19:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f27f987b8bca6d2d67b243594bf73f4e6259e5d6",
          "body": "Map<K,V> @ElementCollection: store entries as (owner FK, key, value[s])\ncollection-table rows. Supports basic and enum (@MapKeyEnumerated\nSTRING/ORDINAL) keys with @MapKeyColumn naming; reuses the existing\nbasic/@Embeddable value contract. @MapKey, @Embeddable keys, and\n@OrderColumn-on-Map are fail-\n[…]\nor: document the dense-list null-element policy, route the\ndefault order column name through the naming strategy (snake_case\n<property>_order), and add @ManyToMany-reject / collision regression tests.",
          "is_bot": false,
          "headline": "feat(core): support @ElementCollection Map and @OneToMany @OrderColumn",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T03:05:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bfd44c903ee08106c98410a8eaad867cfbbda07d",
          "body": "M2: when an entity carries @Version, hard delete now pre-checks the\nprimary (id, version) row via COUNT before touching any secondary rows.\nA stale-version delete fails the optimistic lock before issuing any\nDELETE, so under autocommit the secondary rows (and the primary row) are\npreserved (\"lock fa\n[…]\nble SELECT cannot\n  be locked on PostgreSQL.\n- Document the migration edge: updating a row with no secondary row\n  affects 0 rows silently (no upsert).\n\nAdds H2 end-to-end coverage for all four cases.",
          "is_bot": false,
          "headline": "fix(core): harden @SecondaryTable delete ordering and update scope",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T02:44:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c948b319232b61380b6528e71a4b2a273cdc0ebd",
          "body": "…umnName",
          "is_bot": false,
          "headline": "fix(core): bound @ForeignKey constraint names and honor referencedCol…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T02:43:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6822764e0085800f442a43c75306eb56dabb4d16",
          "body": "Add regression coverage for the high-risk @Temporal branches and clarify\ntwo minor review gaps:\n\n- Combination rejection: @Temporal + @Enumerated/@Json/@Convert and a\n  registered AttributeConverter for the domain type now have unit tests.\n- Dialect temporal DDL: string-level createTable assertions \n[…]\nsion already fixed by the type; map without\n  @Temporal).\n- TemporalAttributeConverter javadoc documents the ZoneId.systemDefault()\n  non-determinism (pin server TZ, DST spring-forward midnight edge).",
          "is_bot": false,
          "headline": "test(core): cover @Temporal rejection paths and dialect tokens",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T02:42:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cd8bcc9d6f44c71426856d195ca8acdea67f7b20",
          "body": "…econdaryTable)\n\nAddress four production-grade issues surfaced by post-merge review of the\nJPA-compat cycle:\n\n- @ForeignKey: addForeignKeys now honors SchemaOptions.ifNotExists — under\n  ddl-auto=UPDATE it queries existing constraint names (information_schema /\n  user_constraints on Oracle) and skip\n[…]\na silently broken insert/read split.\n\nTests: FK repeated-create idempotency (H2 round-trip), SecondaryTable+inheritance\nrejection, MySQL/MariaDB datetime + Oracle TIME/user_constraints dialect tokens.",
          "is_bot": false,
          "headline": "fix(core): close ship-blocker gaps from cycle-A review (FK/Temporal/S…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T02:26:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dbf9d7a4aa7369ed54934d193d24ded45a81a23f",
          "body": "Route columns annotated @Column(table=\"...\") to a JPA @SecondaryTable\nthat shares the primary key. Insert writes the primary row first (to\nobtain a generated key) then each secondary row with the same PK in one\nreactive chain; findById/findAll read primary LEFT JOIN secondary on the\nPK; update propa\n[…]\novered by EntityMetadataFactorySecondaryTableTest (honor/reject) and the\nH2 SecondaryTableIntegrationTest (save/findById/update/delete round-trip,\nasserting rows actually land in the secondary table).",
          "is_bot": false,
          "headline": "feat(core): support @SecondaryTable / @PrimaryKeyJoinColumn",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T02:04:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d1d90beab80a87c40f57a94500b4703a1968dec6",
          "body": null,
          "is_bot": false,
          "headline": "feat(core): support @OrderColumn for ordered collections",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T01:50:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "00974cc53e488bd86f3f9604e028bd87989007ac",
          "body": "Add JPA @ForeignKey source compatibility for DDL/schema generation.\nNova previously emitted no FOREIGN KEY constraints anywhere (entity FK\ncolumns, @JoinTable link tables, @CollectionTable). This honors\n@ForeignKey on @JoinColumn (@ManyToOne/@OneToOne), @JoinTable\n(foreignKey/inverseForeignKey for @\n[…]\n (PostgreSQL/MySQL quoting), resolver\nhonor rules, factory rejection, and an H2 round-trip verifying the\nconstraint actually rejects violating inserts (and NO_CONSTRAINT/\nPROVIDER_DEFAULT allow them).",
          "is_bot": false,
          "headline": "feat(core): honor @ForeignKey constraint mode in schema generation",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T01:49:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6ef82d3c53c3ffe9cd332015c8555cf2482aada9",
          "body": "Accept legacy JPA @Temporal(DATE|TIME|TIMESTAMP) on java.util.Date and\njava.util.Calendar fields by reusing the existing converter +\nconverterColumnType mechanism. A TemporalAttributeConverter round-trips\nDate/Calendar to the java.time storage representation (LocalDate /\nLocalTime / LocalDateTime), \n[…]\nble per dialect.\n\nFail-fast rejections: @Temporal on a java.time type, and a\njava.util.Date/Calendar field missing @Temporal (ambiguous mapping).\n\nNo new PersistentProperty constructor field is added.",
          "is_bot": false,
          "headline": "feat(core): support @Temporal for java.util.Date/Calendar mapping",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T01:47:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fd30fb475d9f642508e28c963360d8f959b01b3c",
          "body": "… document @Access(PROPERTY) relation limitation\n\n- cascadeRemoveToOneReferences deleted the reference using the declared\n  manyToOneTargetType(); for an inheritance subtype reference this targets the wrong\n  table (and a TABLE_PER_CLASS abstract root has no table at all). Use the actual\n  instance \n[…]\ntation that @ManyToOne/@OneToOne are always field-access\n  even under class-level @Access(PROPERTY) (harmless given Nova requires a backing\n  field; only diverges for transforming relation accessors).",
          "is_bot": false,
          "headline": "fix(core): cascade-remove resolves reference by actual instance type;…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T01:17:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0f34e75696cd15d02a11f08d32c95323a7ece701",
          "body": "…ed references\n\nPer JPA, PERSIST cascades only to transient (new) references; MERGE propagates to\nalready-managed ones. The to-one cascade re-saved every reachable reference on each\nowner save (existence-check SELECT + UPDATE up the whole ancestor chain), diverging\nfrom JPA and wasting round-trips. \n[…]\nence stays bound on the owner\nfield so the FK still resolves from its existing id. Added cascadeMergeReference() and\nan H2 test asserting a PERSIST-only cascade does not rewrite a persisted reference.",
          "is_bot": false,
          "headline": "fix(core): @ManyToOne/@OneToOne PERSIST cascade skips already-persist…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T01:12:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "96464048b7402d5ec539b51c2f761c62be30e487",
          "body": "…ion on cycles\n\nA bidirectional cascade=ALL (A->B, B->A) or a self-referential to-one cascade\nre-entered save(reference) without any managed-entity tracking, recursing until\nStackOverflowError. Added an identity-based visited-set shared across the save tree\nvia Reactor Context (CASCADE_VISITED_KEY):\n[…]\ncle handling. The remove cascade\ndoes not recurse (deleteById issues a DELETE without re-cascading), so only the save\npath needed the guard. Added bidirectional and self-reference H2 regression tests.",
          "is_bot": false,
          "headline": "fix(core): guard @ManyToOne/@OneToOne cascade against infinite recurs…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T01:08:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bf99051eebb805e81498428cf350212ece289b3b",
          "body": "… id gaps\n\nUnder concurrency, multiple savers exhausting the same in-memory id block each ran\ntheir own select+compare-and-set refill; the winning CAS blocks are disjoint (so ids\nwere never duplicated), but losing refills overwrote the in-memory cursor, wasting the\nallocated range as id gaps. Now re\n[…]\ncache()+then composition and left the\ncompleted refill pinned (breaking subsequent allocations). refill() no longer returns\nthe first id; callers pull via next() after the (deferred) refill completes.",
          "is_bot": false,
          "headline": "fix(core): single-flight @GeneratedValue(TABLE) block refill to avoid…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T00:53:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "41f430623a80ebf7aa2b8fcd8436b09a34c9ea59",
          "body": "…ollection embeddable validation\n\n- F1: lifecycle/listener callback collection sorted getDeclaredMethods() per class\n  (name + parameter types) so multiple callbacks of the same phase have a\n  deterministic invocation order (class hierarchy order derived->base preserved).\n- F2: @ElementCollection of\n[…]\ng\ncompare-and-set allocation is already duplicate-free; the only downside is id gaps\nunder concurrency, which JPA permits. A single-flight optimization is not worth the\nadded reactive complexity here.",
          "is_bot": false,
          "headline": "fix(core): deterministic listener callback order + stricter @ElementC…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T00:44:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6c51b02222d68d5533ccd5baf64e97e33f16ef8b",
          "body": "- M2: route TABLE_PER_CLASS concrete-type findAll/findById to its own single\n  table instead of a polymorphic UNION + client-side filter. Only the abstract\n  TPC root needs the UNION; JOINED still requires the join (isMultiTableInheritance\n  now returns false for a TPC concrete subtype).\n- M1: count\n[…]\ns (an intermediate\n  @Entity between root and a concrete subtype was silently flattened, violating\n  JPA semantics).\n\nAdded TPC count/exists integration test and a multi-level fail-fast metadata test.",
          "is_bot": false,
          "headline": "fix(core): address multi-table inheritance review backlog (M1/M2/M3)",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T00:22:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "733c9044e2621610ec79aeb4d54e4859f1751e50",
          "body": "… mappings",
          "is_bot": false,
          "headline": "docs(example): add nova-example comparing Nova and Hibernate Reactive…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T00:14:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f31c1e7f28b3a28de475fceb06b4fb96c6bd857",
          "body": null,
          "is_bot": false,
          "headline": "chore: add .claude agent/command/hook tooling config",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-29T00:14:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "49e3a80e79a238cbc35640c17ef1471c557a5a23",
          "body": null,
          "is_bot": false,
          "headline": "feat(core): support cascade on @ManyToOne/@OneToOne relations",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-19T05:04:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d539b9b7ee503169af607eaa9f4eb0ea631fa0a2",
          "body": null,
          "is_bot": false,
          "headline": "feat(core): support @Access(PROPERTY) getter/setter access",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-19T02:56:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ff87cb6491608f885d98492fe1a172560f134c1",
          "body": "…zy proxy)",
          "is_bot": false,
          "headline": "feat(core): accept @ManyToOne/@OneToOne(fetch=LAZY) (no-op without la…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-19T01:51:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4fc9a9d1f26841558b6cecde894227e356cffee9",
          "body": null,
          "is_bot": false,
          "headline": "feat(core): support @MapsId derived identifiers (shared primary key)",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-19T01:25:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4152876eb41ae5e3209416578b36c49e3b6551b5",
          "body": "…beddable), @OneToMany cascade, @GeneratedValue(TABLE), listener exclusions (#37)\n\n* feat(core): support @ExcludeDefaultListeners, @ExcludeSuperclassListeners, and listener inheritance\n\n* feat(core): support @ElementCollection of @Embeddable element types\n\n* feat(core): support @OneToMany cascade an\n[…]\n) — mirroring the TABLE_PER_CLASS path —\nmakes predicate/sort resolve against unambiguous flat columns (and now even\nsupports subtype-column filters). Added renderer + H2 integration regression tests.",
          "is_bot": false,
          "headline": "feat(core): JPA 호환성 — inheritance(JOINED/TPC), @ElementCollection(@Em…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-18T04:35:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1b40bd7f2ce2ae502ccd4e523cfb6f3341a334ab",
          "body": "…s) (#36)\n\nRegister external listener classes via jakarta.persistence.@EntityListeners.\nListener methods carry the standard lifecycle annotations (@PrePersist,\n@PostPersist, @PreUpdate, @PostUpdate, @PostLoad, @PreRemove, @PostRemove) but\ntake the entity as a single argument, complementing the exist\n[…]\nr fires listener callbacks before the entity's own\n  callbacks per phase, in declaration order, per the JPA contract.\n- Unit + H2 integration tests; docs/entities.md gains an Entity listeners section.",
          "is_bot": false,
          "headline": "feat(core): support @EntityListeners (external entity listener classe…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T23:17:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "727289c31776e05c4f2bbfaf09850a106ede9bcf",
          "body": "…tion (#35)\n\nJMH pinned the dominant findById cost as the per-op pooled-connection\nacquire/release under autocommit (~3.85us of ~5.85us). inReadSession binds\none connection to the Reactor Context for the scope (no BEGIN/COMMIT, no\npersistence session) so the reads inside reuse it instead of acquirin\n[…]\n(connection not concurrency-safe); writes autocommit\nwith no scope atomicity — use inTransaction for that. Docs: transactions.md.\nBoth contract additions are additive (default method + new interface).",
          "is_bot": false,
          "headline": "feat(core): inReadSession — connection-scoped reads without a transac…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T08:56:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4b42de72a5c0cf0bc541398ce703ebbe06655666",
          "body": "Adds a JMH harness (me.champeau.jmh plugin) measuring Nova's read/write\nhot paths on H2 in-memory with proper warmup/forks — precise ns/op\nwithout the coarse harness's run-to-run noise.\n\nFindings (us/op): renderSelectById 0.24, findById 5.85, saveInsert 8.34,\nfindAll100 108.9 (~1.09/row). This pins \n[…]\nes, while point-read latency is\nstructural (connection-per-op under autocommit). findAll amortizes the\nfixed cost well, where the row-mapping caching pays off.\n\nRun with: cd benchmark && ./gradlew jmh",
          "is_bot": false,
          "headline": "test(benchmark): add JMH hot-path micro-benchmarks for Nova (#34)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T08:08:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d8e8321121490691db92fe981e1f22b0a9386848",
          "body": "… mapping (#33)\n\nRow mapping was fully reflective per row: instantiate() called\ngetDeclaredConstructor() + setAccessible() on every row, and each column\nwent through Field.get/set.\n\n- Cache the no-arg Constructor per entity type (lookup + setAccessible\n  once), so row decoding no longer repeats the \n[…]\n + field\nwrites) — H2 findAll ~4.8ms -> ~3.4ms per 2000 rows. Single-row findById\ngains are within run noise (per-op connection/reactive cost dominates).\nBehavior-preserving; full build + tests green.",
          "is_bot": false,
          "headline": "perf(core): VarHandle field access + cached entity constructor in row…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T07:52:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "809f834b92d7f0cae65c787b7090a4921a1c2b58",
          "body": "…QL (#32)\n\nTwo hot-path wins found by profiling findById:\n\n1. R2dbcSqlExecutor instrumented every execute/queryOne/queryMany/batch\n   with System.nanoTime() + an AtomicLong row counter + doOnNext/doOnSuccess/\n   doOnError(Complete) callbacks — even when the SqlExecutionListener is\n   NO_OP (the defa\n[…]\nl.\n\nCombined with the earlier metadata-view caching, H2 findById dropped from\n~100ms to ~66ms per 2000 ops (vs Hibernate 2.8x -> 1.88x). Both changes\nare behavior-preserving; full build + tests green.",
          "is_bot": false,
          "headline": "perf: skip query instrumentation when no listener; cache selectById S…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T06:29:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5a6df33e2374542fb3f85c7905eafecde23548a9",
          "body": "…ive (#31)\n\nAdds a flag that drops blocking Hibernate ORM (and the H2 phase) and runs\njust Nova vs Hibernate Reactive on PostgreSQL — a true reactive-vs-reactive\ncomparison.\n\nResult (PG, concurrency=300): Nova wins every latency scenario vs\nHibernate Reactive — INSERT 2.1x, FIND_ALL 4x, DELETE 2.4x,\n[…]\neactive). The leanness shows:\nHibernate Reactive carries the full Hibernate engine (persistence context,\ndirty checking, per-op session bootstrap) on Vert.x, while Nova is a lean\nreactive data-mapper.",
          "is_bot": false,
          "headline": "test(benchmark): add -Dbench.reactiveOnly for Nova vs Hibernate React…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T04:44:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e6d8e2cec3f7713f1963fd5ff7691053b70753e9",
          "body": "…ion ops on no-session reads (#30)\n\nProfiling findById showed two avoidable per-call costs in the read hot path:\n\n1. EntityMetadata's relation/collection views (manyToOne/oneToMany/\n   oneToOneInverse/manyToMany/elementCollection) re-ran stream().filter().\n   toList() on every call, and hasRelationP\n[…]\ninefficiency.\n\nEntityMetadataRelationDerivedTest updated: the derived views are now\ncached + immutable (the prior test pinned per-call re-streaming, which\nthe immutable `properties` made unnecessary).",
          "is_bot": false,
          "headline": "perf(core): cache derived relation views in EntityMetadata; skip sess…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T03:39:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "554e92cb3cd6425578e3a3bfed468a0e0d968908",
          "body": "… PG phase (#29)\n\nAdds a third engine — Hibernate Reactive (non-blocking Hibernate on\nVert.x) — to the PostgreSQL phase, for a true reactive-vs-reactive\ncomparison against Nova (Hibernate ORM blocking stays as the blocking\nbaseline). HR is PG-only (Vert.x has no H2 client). Driven via the\nStage.Sess\n[…]\nnes it's weight vs leanness: HR carries the full Hibernate\nengine and was competitive-to-ahead on concurrent throughput; Nova is\nlean and won single-op INSERT/DELETE outright. See benchmark/README.md.",
          "is_bot": false,
          "headline": "test(benchmark): add Hibernate Reactive (reactive-vs-reactive) to the…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T03:24:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ee9971a090b2cf97c0f331fcd3cb8fd44774bef5",
          "body": "…ncy metric (#28)\n\nAdds a second backend to the harness — PostgreSQL via Testcontainers (or\nan external -Dbench.pg.host) — so the reactive concurrency model is\nobservable under real socket round-trips, not just H2 in-memory. Both\nORMs now use a 20-connection pool with proper queueing (Hibernate via\n\n[…]\no reactive does not out-throughput\nat a fixed pool — its edge is resource efficiency: Nova sustained 200\nconcurrency on 9-20 threads vs Hibernate's ~210-221 (one per request).\nSee benchmark/README.md.",
          "is_bot": false,
          "headline": "test(benchmark): add PostgreSQL (real-latency) phase + thread-efficie…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T03:04:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "540b1b9fecbc631ca51a7b4abbe00709d7e2f788",
          "body": "…(#27)\n\nStandalone composite-build project (not part of the published build) that\nruns the same jakarta.persistence entity through both Nova (reactive,\nR2DBC) and Hibernate ORM (blocking, JDBC) against H2, verifies end-to-end\nCRUD correctness, and profiles latency + concurrent throughput.\n\nBecause N\n[…]\nn zero-latency\nin-memory ops, blocking threads out-throughput reactive under concurrency\n(no I/O wait to overlap) — a Postgres+Testcontainers variant is the\nnatural next step. See benchmark/README.md.",
          "is_bot": false,
          "headline": "test(benchmark): add Nova vs Hibernate ORM E2E + performance harness …",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T02:16:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d35ad039563ff339b1b650e92f884c258d642d48",
          "body": "Bump default dev version to 2.1.0-SNAPSHOT and documentation coordinates\nto 2.1.0. 2.1.0 is additive over 2.0.0: composite keys (@EmbeddedId /\n@IdClass), @OneToOne / @ManyToMany / @ElementCollection, @Convert, and a\ntransaction-bound persistence session.",
          "is_bot": false,
          "headline": "chore(release): prepare 2.1.0 (#26)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T02:01:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f385259a56343f0390a5ed2139128d6dd10b17c8",
          "body": "Add value collections (List/Set of basic types) stored in a separate\ncollection table, complementing @ManyToMany. Reuses the collection-table\nmachinery: auto-created DDL, full-replace write at save, and eager\nhydration (1-hop — values are inline, no target entity).\n\n- Modeling: ElementCollectionInfo\n[…]\n → no\nper-dialect edits.\n\nCovered by EntityMetadataFactoryElementCollectionTest and\nElementCollectionIntegrationTest (H2: DDL, save sync, hydration,\nfull-replace, empty clear). Docs: docs/entities.md.",
          "is_bot": false,
          "headline": "feat(core): support @ElementCollection (basic element types) (#25)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T01:58:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0151352f01c0bf9f345bb2741db81a17f993d391",
          "body": "Add many-to-many associations through an auto-managed link table —\nowning (@JoinTable) and inverse (mappedBy) sides, List and Set, with\nfull-replace write and 2-hop eager hydration. This was the original\nmotivator of the persistence-session epic.\n\n- Modeling: ManyToManyInfo carrier on PersistentProp\n[…]\nanyToManyIntegrationTest (H2: DDL, save link sync,\nboth-side hydration, full-replace, empty clear). Docs: docs/entities.md.\nv1 scope; composite-keyed M2M / @OrderBy / session collection-diff deferred.",
          "is_bot": false,
          "headline": "feat(core): support @ManyToMany / @JoinTable (#24)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T01:45:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "13c4afc4fe0b374d1c3ce32fc6e89de1fc544e5e",
          "body": "…ty checking) (#23)\n\nIntroduce a reactive unit-of-work session that activates inside\ninTransaction(). It rides the Reactor Context as a sibling of the\nconnection key (no ThreadLocal), so existing operations transparently\ngain JPA-style identity and automatic change tracking. Outside a\ntransaction ev\n[…]\n, rollback,\n@Version). Adds H2IntegrationTestSupport.createWithManagedTransactions().\n\nDocs: docs/transactions.md. v1 scope; cascade / @ManyToMany join /\ndetached-merge / session-spanning-tx deferred.",
          "is_bot": false,
          "headline": "feat(core): transaction-bound persistence session (identity map + dir…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-15T00:16:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "95c09a7ae56943f57d312d43ee0849e2d3534eb5",
          "body": "Model a composite primary key as several top-level @Id fields plus a\nmirror id class, complementing @EmbeddedId. Multiple @Id fields are now\npermitted when the entity carries @IdClass.\n\n- EntityMetadata.readIdValue() constructs an id-class instance from the\n  entity's @Id values; idColumnValue() dec\n[…]\nctor, at least two @Id fields, and no\n  mixing with @EmbeddedId.\n\nCovered by EntityMetadataFactoryIdClassTest (metadata/rejection) and\nIdClassIntegrationTest (H2 insert/update/find/delete round-trip).",
          "is_bot": false,
          "headline": "feat(core): support @IdClass composite keys (#22)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-14T23:32:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ce3df2655383da646b39a3a3c8511597d7a02881",
          "body": "Model a multi-column primary key as an @Embeddable key type referenced by\n@EmbeddedId. The key fields flatten into the entity table without a\nhost-field prefix (unlike @Embedded) and are marked as id properties.\n\n- EntityMetadata exposes idProperties()/hasCompositeId()/readIdValue();\n  idProperty() \n[…]\n\n  path.\n- @GeneratedValue on a key component is rejected.\n\nCovered by EntityMetadataFactoryEmbeddedIdTest (metadata/rejection) and\nEmbeddedIdIntegrationTest (H2 insert/update/find/delete round-trip).",
          "is_bot": false,
          "headline": "feat(core): support @EmbeddedId composite keys (#21)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-14T23:20:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9ef59b0957b2583a944bb22eea99f29c2f45fb16",
          "body": "Add JPA @OneToOne in both directions, reusing the existing relation\nhydration infrastructure.\n\n- Owning side (@JoinColumn, no mappedBy): carries a unique FK column and is\n  modeled exactly like @ManyToOne (manyToOne=true), so read/write stub,\n  insert/select, and withReferencedParent hydration all a\n[…]\nker excluded from column mapping\n  and uniqueness checks.\n\nFactory unit tests (owning FK/unique, inverse marker, reject lazy/cascade/\nconflict) + bidirectional H2 integration round-trip. Docs updated.",
          "is_bot": false,
          "headline": "feat(core): support @OneToOne (owning and inverse) (#20)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-12T05:41:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "947d1c2a20537f7a075d4e1d68f1873ced9a252b",
          "body": "…ter (#19)\n\nMap an arbitrary field type to a column via JPA's standard\n@Convert(converter = X.class) + jakarta.persistence.AttributeConverter<X, Y>,\nreplacing the divergence where Nova only had its own io.nova.convert SPI +\nprogrammatic registerConverter.\n\n- EntityMetadataFactory reads @Convert, ins\n[…]\nApply=true) and @Convert(attributeName);\nuse registerConverter for type-wide application.\n\nFactory unit tests (apply/columnType/conflict/no-arg-ctor/disable) + H2 integration\nround-trip. Docs updated.",
          "is_bot": false,
          "headline": "feat(core): support @Convert with jakarta.persistence.AttributeConver…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-12T05:13:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "58bcd6005f2199119bff25b159715d432db50a11",
          "body": "Bump documented Maven coordinates and the default SNAPSHOT to 2.0.0. This is a\nbreaking release: entities are mapped with standard jakarta.persistence\nannotations (#14, #15) replacing the 1.x io.nova.annotation clones, plus\n@AttributeOverride/@Lob/@OrderBy/column-level validate (#16) and\n@Inheritance(SINGLE_TABLE) (#17).",
          "is_bot": false,
          "headline": "chore(release): prepare 2.0.0 (#18)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-12T01:39:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0272564486e1b9758d931a6f234fed9ccde4e503",
          "body": "Map an entity hierarchy onto one table with a discriminator column, matching\nJPA's InheritanceType.SINGLE_TABLE.\n\n- EntityMetadataFactory detects the hierarchy root (@Inheritance or topmost\n  @Entity ancestor), parses @DiscriminatorColumn/@DiscriminatorValue, walks\n  @Entity ancestors for inherited \n[…]\nA persistence-unit style, regardless of nova.ddl-auto.\n\nUnit tests (factory honor/reject, renderer/DDL) + H2 integration test\n(save → polymorphic findById/findAll → subtype restriction). Docs updated.",
          "is_bot": false,
          "headline": "feat(core): support @Inheritance(SINGLE_TABLE) (#17)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-12T01:16:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "627b2d6778ea3568bd5f61611ae8860f6ed7bdda",
          "body": "…ma)…, column-level validate (#16)\n\n* feat(core): support @AttributeOverride on @Embedded columns\n\n@AttributeOverride(name = \"city\", column = @Column(name = \"ship_city\")) on an\n@Embedded field now overrides the composed column name of the embeddable\nsub-property with the given absolute name; sub-pro\n[…]\nlizer.validate\n  queries the dialect column catalog (Dialect.listColumnsSql, default\n  information_schema.columns; Oracle user_tab_columns) and reports missing\n  columns per table, case-insensitively.",
          "is_bot": false,
          "headline": "feat: more JPA gaps — @AttributeOverride, @Lob, @OrderBy, @Table(sche…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-12T00:07:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8e53f28040b02de3188b52d08ba3448488eb024e",
          "body": "…n/relation attrs, ddl-auto) (#15)\n\n* feat(core)!: adopt jakarta.persistence for full JPA source compatibility\n\nReplace Nova's hand-written io.nova.annotation clones with the real JPA\nannotations from jakarta.persistence, so a JPA entity is source-compatible\nas-is (same imports, same attributes). Th\n[…]\nnd fails\n  startup with the missing tables instead of throwing unconditionally.\n\nCovered by an H2 end-to-end test (validate errors before create, completes\nafter) and a starter bean-registration test.",
          "is_bot": false,
          "headline": "feat(core)!: extend JPA source compatibility (jakarta adoption, colum…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-11T23:02:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1358b9c76c55366a2bf187834794f1d6d6a2c281",
          "body": "Make Nova's io.nova.annotation surface match jakarta.persistence wherever\nit diverged, while keeping the lean reactive semantics (no lazy loading,\nno persistence context).\n\n- @Table / @Column: rename value() -> name(); the JPA-incompatible\n  shorthand @Column(\"x\") becomes @Column(name = \"x\") across \n[…]\ne), GenerationType.NONE, and\ntype-level @Index/@UniqueConstraint are removed. Entities must use\n@Table(name=...)/@Column(name=...), drop NONE, and declare indexes and\nunique constraints inside @Table.",
          "is_bot": false,
          "headline": "feat(core)!: align annotation syntax with JPA (#14)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-11T14:41:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f69fc12f74c949633e70bce3b130c61fb3c8b408",
          "body": "The current categories all key on labels. A PR merged with no labels — as\nhappened for PRs #4-#7, which landed before boring-cyborg started doing\npath-based labeling — was rendered in the draft without a category heading,\nhiding it inside the surrounding markdown. The new \"Other changes\" category\nus\n[…]\ncken-and-egg case where a release-drafter-introducing PR omits\nitself from its own first draft (the other half of #8) is a one-time\nartifact and resolves naturally on the next push to main.\n\nCloses #8",
          "is_bot": false,
          "headline": "fix(ci): add release-drafter catch-all category for unlabeled PRs (#9)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-11T05:49:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "475bf5de9bbb456df81c934904d115aee0d7561b",
          "body": "…pository (#13)\n\nCloses #12.\n\nExtends the existing ReactiveCrudRepository proxy to parse method names that\nfollow a Spring Data-style derived convention. Anything the fixed-name switch\ndoes not match (save, findById, findAll, ...) falls through to the new derived\nquery parser; if that succeeds, it d\n[…]\nue #12):\n- L1 (merged #11): nova-metamodel - compile-time property-name constants.\n- L2 (this PR):    nova-spring-data derived queries.\n- L3 (later):      nova-querydsl - typed path DSL, builds on L1.",
          "is_bot": false,
          "headline": "feat(spring-data): add derived query method support on ReactiveCrudRe…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-10T05:59:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "00813eac54e74b141f8d552fd69f656dac7b2952",
          "body": "…time property constants (#11)\n\nCloses #10.\n\nIntroduces an opt-in module `nova-metamodel` that scans `@Entity` classes at\ncompile time and emits a JPA-style `<EntityName>_` companion class per entity.\nEach companion exposes the entity's persistent property names as\n`public static final String` const\n[…]\n):\n- L1 (this PR): nova-metamodel — property-name constants.\n- L2 (next):    nova-spring-data-derived — Spring-Data-style derived queries.\n- L3 (later):   nova-querydsl — typed path DSL, builds on L1.",
          "is_bot": false,
          "headline": "feat(metamodel): add nova-metamodel annotation processor for compile-…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-10T05:09:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1988be2afc7fb0b1d9e40ac0494f32b41829cbb9",
          "body": "…er (#7)\n\n* ci: add boring-cyborg and release-drafter for lightweight triage\n\nReplace heavyweight LLM PR review with the deterministic GitHub Action /\nGitHub App stack that Apache Airflow and most Spring projects use.\n\n- .github/boring-cyborg.yml — config for Airflow's same labeling bot\n  (kaxil/bor\n[…]\n yet have .github/release-drafter.yml. Label automation is owned by\nboring-cyborg, so release-drafter does not need the pull_request hook\neither way. Drop the trigger and add a comment explaining why.",
          "is_bot": false,
          "headline": "ci: replace CodeRabbit auto-review with boring-cyborg + release-draft…",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-09T06:38:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d37493576de6ab62a6829979474d4a4895913715",
          "body": "* feat(core): add SchemaInitializer and idempotent SchemaGenerator DDL\n\nCloses the user-facing half of issue #2 (schema-from-entity helper).\n\nAdds io.nova.schema package — DdlAuto enum, SchemaOptions, SchemaInitializer\ninterface, and SimpleSchemaInitializer impl that issues DDL through\nReactiveEntit\n[…]\n  novaSchemaBootstrapRunner entries, new \"Schema bootstrap (nova.ddl-auto)\"\n  section explains modes and the InitializingBean lifecycle, properties\n  table adds nova.ddl-auto and nova.entity-packages.",
          "is_bot": false,
          "headline": "feat: add SchemaInitializer + nova.ddl-auto (Phase 1) (#6)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-09T06:31:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "01e5e4a21ef1e57b052db243ecce68ef4386845a",
          "body": "* docs: add CODEOWNERS for path-based review routing\n\n@guhyunwoo를 모든 경로의 default owner로 지정해 PR 발생 시 자동 review\nrequest가 가도록 한다. 모듈별 책임이 분화되면 path-specific override를\n추가해 dialect 모듈은 dialect 담당자, docs는 docs 담당자 식으로 라우팅을\n세분화할 수 있다.\n\nGitHub의 LAST-match-wins 규칙에 따라 govern·build·core·dialects·spring·\ndocs를\n[…]\net (root README,\ndocs/, CONTRIBUTING, issue/PR templates, CODEOWNERS comments) is in\nEnglish so that international contributors can read and contribute to\nthe project's documentation surface.\n\nRefs #1",
          "is_bot": false,
          "headline": "docs: add CODEOWNERS and translate all docs to English (#5)",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-09T04:21:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9bc6c28ecc03f0cd5f5a60d596f16d75600980e8",
          "body": "docs: split README into docs/, fix unrunnable quickstart, add CONTRIBUTING",
          "is_bot": false,
          "headline": "Merge pull request #4 from bssm-oss/docs/restructure-and-contributing",
          "author_name": "구현우",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-08T08:25:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c614c1c76baa85b6123e850edd570702ac7d04d8",
          "body": "이슈 / PR / 커밋 메시지 형식이 비규격이라 재현 정보·테스트 계획·breaking\nchange 표기가 일관되지 않는 문제를 해결한다. AGENTS.md는 코드 컨벤션만\n다루므로 작업 흐름과 메시지 형식을 CONTRIBUTING.md로 분리한다.\n\nCONTRIBUTING.md 핵심:\n- Conventional Commits 타입(feat/fix/docs/refactor/test/perf/build/ci/chore\n  /style) + 권장 scope(core/r2dbc/dialect-*/spring-boot/spring-data\n[…]\n도 (Discussions 우선 안내)\n\n.github/ISSUE_TEMPLATE/config.yml로 blank issue 비활성화 + docs /\nAGENTS.md / CONTRIBUTING.md contact link 노출.\n\nPULL_REQUEST_TEMPLATE.md는 위 CONTRIBUTING의 PR 규격을 그대로 자동 채워준다.\n\nRefs #1",
          "is_bot": false,
          "headline": "docs: add CONTRIBUTING guide and issue/PR templates",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-08T07:55:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "105cba143232be190cfa9a41f6651d6e6fce403f",
          "body": "…start\n\n루트 README가 996줄까지 부풀어 docs 역할을 겸하던 구조를, 성숙한 OSS 컨벤션을\n따라 canonical 형태(태그라인 / install / quickstart / docs 링크 / Requirements\n/ Modules / Build / Roadmap)로 198줄까지 트림하고 상세 내용을 docs/ 하위 7개\n페이지로 분리한다.\n\nGetting started의 placeholder(`/* SimpleReactiveEntityOperations 구성 */`)를\n제거하고 io.github.bssm-oss:\n[…]\n+ nova-spring-data\n- docs/observability.md    — SqlExecutionListener + Micrometer + pool\n\n정보 손실 없음 — 모든 예제·표·운영 caveat 그대로 이전. Project Focus /\nPrinciples / Project layout 등 사용자 가치가 낮은 섹션만 제거.\n\nRefs #1",
          "is_bot": false,
          "headline": "docs(readme): split into focused docs/ pages and fix unrunnable quick…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-08T07:55:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "780eeea0df70a888a734e0d4fa3f8e7aff7f347b",
          "body": "…n list\n\nAbstractSchemaGenerator.createTable이 metadata.properties() raw view를\niterate하면서 OneToMany inverse field(예: List<Book> books)까지 컬럼\n정의에 넣으려 했다. sqlType은 java.util.List를 매핑할 수 없어\nIllegalArgumentException(\"Unsupported column type: java.util.List\")으로\n실패했다. 같은 EntityMetadata API의 다른 호출자(alterTabl\n[…]\nperties() 뷰를 사용한다.\n\ncreateTable도 동일한 뷰를 사용하도록 정렬한다. 회귀를 막기 위해\nAuthorWithBooksAnnotated/BookWithAuthorAnnotated 쌍으로 OneToMany 부모는\ninverse 필드를 컬럼으로 만들지 않고, ManyToOne 자식은 FK 컬럼을 단일로\n만드는지를 검증하는 테스트를 추가한다.",
          "is_bot": false,
          "headline": "fix(schema): exclude @OneToMany inverse fields from createTable colum…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-01T07:07:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "351a8f2e280ecdf12e8a915d0bce2e13f58245e6",
          "body": "1.0.0 GA가 Central에 published됐으므로 dev 빌드의 기본 버전을 다음\npatch dev 라인으로 올린다. release 워크플로는 그대로 git tag v<x>에서\n값을 파생하므로 동작 변경 없음.",
          "is_bot": false,
          "headline": "chore(build): bump default version to 1.0.1-SNAPSHOT for next dev cycle",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-01T06:22:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "317ede46c6bdf969313173b86b14507ae9684400",
          "body": "…lestone\n\n1.0.0이 Maven Central GA로 배포됨에 따라 dependency 예시를 SNAPSHOT\n좌표에서 정식 좌표로 교체하고 mavenLocal/SNAPSHOT 회피 가이드를 제거한다.\nSNAPSHOT 사용자를 위해 Central snapshots 저장소 안내를 별도로 추가한다.",
          "is_bot": false,
          "headline": "docs(readme): update install examples to 1.0.0 GA and mark roadmap mi…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-06-01T06:22:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "25fdc8b14e425978b60315b972bce7c8dd4366cf",
          "body": "OSSRH Staging API compat 엔드포인트로의 PUT 업로드만으로는 Central Portal\nDeployments 페이지에 노출되지 않는다. publish 단계 직후 같은 runner IP에서\n`POST /manual/upload/defaultRepository/<namespace>?publishing_type=automatic`\n을 호출해 staging을 Portal로 이관하고 검증 통과 즉시 자동 release되도록 한다.\n\nSNAPSHOT 버전은 transfer 단계가 의미가 없어 skip한다.",
          "is_bot": false,
          "headline": "ci(release): transfer OSSRH staging to Central Portal after upload",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-29T05:44:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "755e22b0e9928e7b27b063620c516bc56cc3ed7b",
          "body": "git tag v* push 시 .github/workflows/release.yml이 Sonatype Central Portal로 publish한다.\nbuild.gradle.kts의 version은 기본 1.0-SNAPSHOT이며, 워크플로가 tag(예: v1.0.0)에서 'v'를\n떼고 -Pnova.version=1.0.0으로 주입하면 그 값이 우선한다(findProperty 폴백 추가). -SNAPSHOT\nsuffix 여부에 따라 기존 publishing repositories 분기가 snapshots/staging을 자동 선택한다.\n\npublish 전에 ./gradlew build로 전 모듈 test/assemble을 한 번 더 돌려 깨진 상태로 Central에\n올라가는 사고를 방지한다. 자격증명은 GitHub Secrets(CENTRAL_USERNAME/PASSWORD,\nSIGNING_KEY/PASSWORD)에서 env로 주입 — 코드/로그에 평문이 남지 않는다.",
          "is_bot": false,
          "headline": "ci: add Maven Central release workflow triggered by version tags",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-28T10:43:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc6451a3f0e23b36149b748d78be447fb42f2173",
          "body": "…al POM metadata\n\ngroupId를 io.nova에서 io.github.bssm-oss로 변경한다 — Central Portal의 GitHub 기반 namespace\n검증(io.github.<org>)으로 도메인 소유 없이 io.nova 대신 발행 가능하다. POM url/developer/scm\nplaceholder(nova-orm/*.example)를 실제 repo(bssm-oss/nova-reactive) 좌표로 채우고 TODO(GA)\n마커를 제거한다. README의 의존성 좌표 예시도 io.github.bssm-oss로 갱신한다.\n\nversion은 1.0-SNAPSHOT 유지 — 먼저 snapshots 발행으로 인증/파이프라인을 검증한 뒤 GA 때\n1.0.0으로 bump한다.",
          "is_bot": false,
          "headline": "chore(build): set Maven coordinates to io.github.bssm-oss and fill re…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-28T00:40:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6898af8d45390a183c37ec9909cda92f29389c45",
          "body": "…roadmap",
          "is_bot": false,
          "headline": "docs: note @Column(length/precision/scale) and BigDecimal support in …",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-27T10:09:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "418653a109a0491cd5af4b12f49724761657b62f",
          "body": "…nd scale-default footgun\n\nBigDecimal round-trip 통합 테스트가 수동 DDL 대신 schema generator의 createTableSql 출력을\n실행하도록 바꿔, @Column(precision, scale)이 emit한 numeric(12, 2) DDL을 실제 H2 driver가\n수용하는지까지 end-to-end로 고정한다.\n\nscale을 생략한 @Column(precision = 10)이 numeric(10, 0)으로 emit되어 소수부가 잘리는\n동작(JPA 관례와 동일)을 ColumnTypedEntity fixture + schema 테스트로 명시 고정해, 통화 컬럼에서\n흔한 scale 누락 실수의 결과를 문서화한다.",
          "is_bot": false,
          "headline": "test(schema): harden BigDecimal coverage with generator-emitted DDL a…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-27T10:07:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b726249c5621503bb801f61993f425f1ccf47380",
          "body": "…block",
          "is_bot": false,
          "headline": "chore(build): centralize JUnit test dependencies in root subprojects …",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-27T08:39:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "19bb4783096276d420fa2c06965b1ff700c33d32",
          "body": "…columns\n\nAdd length/precision/scale attributes to @Column and propagate them through\nPersistentProperty so the base schema generator can emit varchar(length) and\nnumeric(precision, scale). BigDecimal becomes a first-class column type:\nAbstractSchemaGenerator and OracleSchemaGenerator now map it to\n\n[…]\nth decodes numeric columns natively as BigDecimal.\n\nprecision/scale are not dead config: an H2 round-trip integration test proves a\nnumeric(12, 2) column is restored exactly through save()/findById().",
          "is_bot": false,
          "headline": "feat(schema): support @Column(length/precision/scale) and BigDecimal …",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-27T08:39:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f92bb6c172ad02215cc63ff55b072f3536971eca",
          "body": "…paths",
          "is_bot": false,
          "headline": "test(spring-boot): cover dialect auto-detection failure and recovery …",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-27T08:39:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "49dfab057d4a02d9cb4c88319cddaf0ba5000ca1",
          "body": "…lause hook",
          "is_bot": false,
          "headline": "test(sql): pin exists() to delegate row-limit through existsRowLimitC…",
          "author_name": "Hyunwoo Gu",
          "author_login": "guhyunwoo",
          "committed_at": "2026-05-27T08:27:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 18,
      "commits_last_year": 246,
      "latest_release_at": "2026-07-20T08:48:20Z",
      "latest_release_tag": "v2.10.0",
      "releases_from_tags": false,
      "days_since_last_push": 4,
      "active_weeks_last_year": 11,
      "days_since_latest_release": 4,
      "mean_days_between_releases": 0.3
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 75,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 0,
      "stars": 4,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "example"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "benchmark/build.gradle.kts",
        "build.gradle.kts",
        "nova-project/nova-cache/build.gradle.kts",
        "nova-project/nova-core/build.gradle.kts",
        "nova-project/nova-dialects/nova-dialect-h2/build.gradle.kts",
        "nova-project/nova-dialects/nova-dialect-mariadb/build.gradle.kts",
        "nova-project/nova-dialects/nova-dialect-mysql/build.gradle.kts",
        "nova-project/nova-dialects/nova-dialect-oracle/build.gradle.kts",
        "nova-project/nova-dialects/nova-dialect-postgresql/build.gradle.kts",
        "nova-project/nova-example/build.gradle.kts",
        "nova-project/nova-metamodel/build.gradle.kts",
        "nova-project/nova-metrics-micrometer/build.gradle.kts",
        "nova-project/nova-r2dbc/build.gradle.kts",
        "nova-project/nova-spring-boot-starter/build.gradle.kts",
        "nova-project/nova-spring-data/build.gradle.kts",
        "nova-project/nova/build.gradle.kts"
      ],
      "largest_source_bytes": 296519,
      "source_files_sampled": 483,
      "oversized_source_files": 8,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 5527
    },
    "dependencies": {
      "manifests": [
        "benchmark/build.gradle.kts",
        "build.gradle.kts"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "maven"
      ],
      "dependencies": [],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 56,
        "open_issues": 0,
        "closed_ratio": 1,
        "closed_issues": 6,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "guhyunwoo",
          "commits": 246,
          "avatar_url": "https://avatars.githubusercontent.com/u/162293672?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "release-drafter.yml",
        "release.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": true,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 8,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": null,
            "reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 0,
            "reason": "0 out of 25 merged PRs checked by a CI test -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 5 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 10,
            "reason": "GitHub workflow tokens follow principle of least privilege",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "205ff7ae934d89b9a879f7241b940a5d30725319",
        "ran_at": "2026-07-24T13:03:22Z",
        "aggregate_score": 4.6,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-20T08:48:22Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-17T15:13:29Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/bssm-oss/nova-reactive",
    "host": "github.com",
    "name": "nova-reactive",
    "owner": "bssm-oss"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 56,
      "inputs": {
        "security": 46,
        "vitality": 77,
        "community": 40,
        "governance": 51,
        "engineering": 62
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 77,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 62,
            "inputs": {
              "commits_last_year": 246,
              "human_commit_share": 1,
              "days_since_last_push": 4,
              "active_weeks_last_year": 11
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "11/52 weeks with commits",
                "points": 7.6,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 11
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "246 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 246
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 18,
              "latest_release_tag": "v2.10.0",
              "releases_from_tags": false,
              "days_since_latest_release": 4,
              "mean_days_between_releases": 0.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "18 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 18
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.3 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.3
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 40,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 8,
            "inputs": {
              "forks": 0,
              "stars": 4,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "4 stars",
                "points": 7.7,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 77,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 6.3,
                "status": "met",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 51,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "merged_prs": 56,
              "open_issues": 0,
              "closed_issues": 6,
              "issue_closed_ratio": 1,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "100% of issues closed",
                "points": 46.8,
                "status": "met",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "56/56 decided PRs merged",
                "points": 38.2,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 56,
                      "decided": 56
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "followers": 20,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "bssm-oss",
              "public_repos": 98,
              "account_age_days": 130
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "20 followers of bssm-oss",
                "points": 9.5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 20,
                      "login": "bssm-oss"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "98 public repos, account ~0 yr old",
                "points": 13.7,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 98
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 62,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 54,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "0 out of 25 merged PRs checked by a CI test -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 46,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Branch-Protection, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "branch_protection",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 46,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 4.6
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "0 out of 25 merged PRs checked by a CI test -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "GitHub workflow tokens follow principle of least privilege",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 1
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 65,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 5527
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 46,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "benchmark/build.gradle.kts",
                "build.gradle.kts",
                "nova-project/nova-cache/build.gradle.kts",
                "nova-project/nova-core/build.gradle.kts",
                "nova-project/nova-dialects/nova-dialect-h2/build.gradle.kts",
                "nova-project/nova-dialects/nova-dialect-mariadb/build.gradle.kts",
                "nova-project/nova-dialects/nova-dialect-mysql/build.gradle.kts",
                "nova-project/nova-dialects/nova-dialect-oracle/build.gradle.kts",
                "nova-project/nova-dialects/nova-dialect-postgresql/build.gradle.kts",
                "nova-project/nova-example/build.gradle.kts",
                "nova-project/nova-metamodel/build.gradle.kts",
                "nova-project/nova-metrics-micrometer/build.gradle.kts",
                "nova-project/nova-r2dbc/build.gradle.kts",
                "nova-project/nova-spring-boot-starter/build.gradle.kts",
                "nova-project/nova-spring-data/build.gradle.kts",
                "nova-project/nova/build.gradle.kts"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "benchmark/build.gradle.kts, build.gradle.kts, nova-project/nova-cache/build.gradle.kts (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "benchmark/build.gradle.kts, build.gradle.kts, nova-project/nova-cache/build.gradle.kts"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Java (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Java"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 99,
            "inputs": {
              "primary_language": "Java",
              "largest_source_bytes": 296519,
              "source_files_sampled": 483,
              "oversized_source_files": 8
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Java (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Java"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "8/483 source files over 60KB",
                "points": 54.1,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 483,
                      "oversized": 8
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "example"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "example",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "example"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-24T13:03:40.073215Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/b/bssm-oss/nova-reactive.svg",
  "full_name": "bssm-oss/nova-reactive",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v1.13.0, esquema v0.27.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadas.