sourcecode 1.64.0__tar.gz → 1.65.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sourcecode-1.64.0 → sourcecode-1.65.0}/CHANGELOG.md +54 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/PKG-INFO +33 -3
- {sourcecode-1.64.0 → sourcecode-1.65.0}/README.md +32 -2
- {sourcecode-1.64.0 → sourcecode-1.65.0}/pyproject.toml +1 -1
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/hibernate_strat.py +102 -2
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/integration_detector.py +31 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/migrate_check.py +266 -68
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/path_filters.py +33 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/.gitignore +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/.ruff.toml +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/CONTRIBUTING.md +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/LICENSE +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/SECURITY.md +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/raw +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/cache.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/cli.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/explain.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/license.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/supabase/functions/README.md +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-1.64.0 → sourcecode-1.65.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.65.0] — 2026-06-30
|
|
4
|
+
|
|
5
|
+
### Fixed — non-Spring / already-modernized repos no longer fabricate blockers (`migrate-check`)
|
|
6
|
+
|
|
7
|
+
A Pro audit of a real enterprise repo (**Keycloak**, Quarkus 3.33 / Jakarta EE /
|
|
8
|
+
Hibernate ORM 6.2.13, Jakarta migration **complete**, 7,885 Java files / 186
|
|
9
|
+
modules) exposed a cluster of false positives that produced `readiness 0/100`, a
|
|
10
|
+
phantom `hibernate_rewrite` headline, and a `boot3` dimension marked applicable
|
|
11
|
+
with **zero** Spring. A migration verdict shown to a CTO must never contradict its
|
|
12
|
+
own evidence. Keycloak is now a golden regression fixture
|
|
13
|
+
(`tests/test_migrate_check_keycloak_regression.py`).
|
|
14
|
+
|
|
15
|
+
- **Hibernate version is resolved before any 5→6 verdict (BUG #1).** The effective
|
|
16
|
+
Hibernate version is parsed from build descriptors, following Maven
|
|
17
|
+
`${properties}` and BOM-managed `<hibernate*.version>` values plus explicit
|
|
18
|
+
`hibernate-core`/`hibernate-orm` coordinates. Major ≥ 6 → the 5→6 axis is **N/A**
|
|
19
|
+
(migration already done), never a blocker. Unresolved version → low-confidence
|
|
20
|
+
hypothesis, **no** `headline_blocker`. New `hibernate.effective_version`,
|
|
21
|
+
`version_major`, `version_confidence`, `migration_applicable`.
|
|
22
|
+
- **Boot3 dimension auto-disables without Spring (BUG #2).** `boot3.applicable` is
|
|
23
|
+
now a function of real Spring usage (build coordinate or `org.springframework`
|
|
24
|
+
import). Quarkus / Micronaut / Jakarta-pure repos report `boot3` as N/A instead
|
|
25
|
+
of a contradictory `applicable: true`.
|
|
26
|
+
- **Jakarta scorer ignores permanent `javax.*` (BUG #3).** The JDK/JSR allowlist
|
|
27
|
+
(`javax.xml.*`, `javax.crypto.*`, `javax.naming.*`, `javax.sql.*`,
|
|
28
|
+
`javax.management.*`, `javax.security.auth.*`, …) is honored end-to-end, so the
|
|
29
|
+
Keycloak's 1,065 permanent `javax.*` imports stop counting as jakarta debt.
|
|
30
|
+
- **Readiness headline can no longer be a misleading 0 (BUG #4).** Framework
|
|
31
|
+
blockers (jakarta / Boot3 / Security) deduct uncapped; orthogonal JDK debt is
|
|
32
|
+
advisory-capped and best-practice hygiene is excluded — so an already-modernized
|
|
33
|
+
repo reads high (Keycloak 85/100), never 0. The headline cannot contradict its
|
|
34
|
+
own note.
|
|
35
|
+
- **Effort excludes N/A axes (BUG #5).** `estimated_effort_days` is computed over
|
|
36
|
+
product (`main`) findings only; the phantom Hibernate 5→6 effort is gone.
|
|
37
|
+
- **Best-practice hygiene no longer sinks a dimension (BUG #6).**
|
|
38
|
+
`java.util.Date`/`Calendar` (MIG-016, `java_8_best_practice`) is reported as a
|
|
39
|
+
separate `hygiene_findings` metric and excluded from JDK-modernization scoring.
|
|
40
|
+
- **MIG-006 explanation matches the actual symbol (BUG #7).** The explanation now
|
|
41
|
+
names the detected `javax.annotation.*` symbol instead of a fixed
|
|
42
|
+
`@PostConstruct/@PreDestroy/@Resource` blurb. `javax.annotation.Generated` (JSR-250,
|
|
43
|
+
emitted into autogenerated SCIM/JAXB sources) is downgraded to **low** and bucketed
|
|
44
|
+
as `generated`.
|
|
45
|
+
- **Test/fixture findings segregated from `blocking_count` (BUG #8).** Findings in
|
|
46
|
+
test harness modules (`testsuite/`, `test-framework/`, `integration-arquillian/`,
|
|
47
|
+
`*-test*`) and under `src/test/` are tagged `code_context: test`; autogenerated
|
|
48
|
+
sources `generated`. Only `main` counts toward `blocking_count`, readiness, and
|
|
49
|
+
effort. The other buckets surface in `non_blocking{}`. Keycloak's 10 test `web.xml`
|
|
50
|
+
+ 14 test-framework `sun.*` no longer inflate the verdict (`blocking_count` 30 → 6).
|
|
51
|
+
- **`export --integrations` is no longer Spring-centric (BUG #9).** Detection now
|
|
52
|
+
covers plain-Java/Jakarta HTTP clients (JDK `HttpClient`, Apache, OkHttp), JNDI
|
|
53
|
+
LDAP, and JavaMail/SMTP in addition to Spring templates, and emits an explicit
|
|
54
|
+
`confidence` (`observed` / `not_analyzed`) + `coverage_note` rather than an
|
|
55
|
+
authoritative `0`. Keycloak: 0 → 144 integrations (80 HTTP / 33 LDAP / 31 SMTP).
|
|
56
|
+
|
|
3
57
|
## [1.64.0] — 2026-06-30
|
|
4
58
|
|
|
5
59
|
### Fixed — zero false-positive blockers (`migrate-check` / `endpoints`)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.65.0
|
|
4
4
|
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Keywords: agents,ai,codebase,context,developer-tools,llm
|
|
@@ -411,7 +411,7 @@ Emits **structured, tool-agnostic** codebase views as plain JSON/YAML — the ki
|
|
|
411
411
|
|------|--------|
|
|
412
412
|
| `--by-directory` | One group per source directory, each symbol with a `source_file:line` reference. |
|
|
413
413
|
| `--module-graph` | `{nodes, edges, summary}` — directories as modules, inter-module dependencies rolled up from class-level relation edges with hit counts + edge types. |
|
|
414
|
-
| `--integrations` | Outbound integrations (`RestTemplate`, `WebClient`, `@FeignClient`, `LdapTemplate`, `
|
|
414
|
+
| `--integrations` | Outbound integrations across Spring **and** plain-Java/Jakarta stacks: HTTP (`RestTemplate`, `WebClient`, `@FeignClient`, JDK `HttpClient`, Apache, OkHttp), LDAP (`LdapTemplate`, JNDI `InitialDirContext`/`LdapContext`), SMTP (`JavaMailSender`, JavaMail `Transport`/`MimeMessage`), and JMS — with `file:line` evidence and a literal `target` when present. Emits an explicit `confidence` (`observed` / `not_analyzed`) + `coverage_note`: a count of `0` means "no client construct found", **not** "no integrations" (runtime/DI-wired clients are not statically visible). |
|
|
415
415
|
| `--c4` | Unified document: `c4.{context, containers, components, code}` + `api_surface` + a `manifest` with per-directory content hashes for **incremental** consumers (skip directories whose hash is unchanged). `components.module_roots` rolls leaf source dirs up to architectural module roots and classifies each `layered` (DDD: ≥2 of `domain`/`application`/`infrastructure`) vs `flat` (legacy/flat package), with a verifiable `module_count` — so a consumer enumerates real modules instead of inferring boundaries from leaf directories. |
|
|
416
416
|
|
|
417
417
|
The section flags compose (pass several for one multi-section document); `--c4` assembles the full export on its own. URLs assembled at runtime yield `target: null` (honest absence, never a guess); containers are derived from build files (Maven/Gradle) and reported as a limitation when none are found.
|
|
@@ -610,7 +610,7 @@ Detects migration blockers across Java source files, Spring XML config files, an
|
|
|
610
610
|
| `MIG-002` | high | `javax.servlet` import — Servlet API changed |
|
|
611
611
|
| `MIG-003` | high | `javax.validation` import — Bean Validation changed |
|
|
612
612
|
| `MIG-004` | high | `javax.transaction` import — TX API changed |
|
|
613
|
-
| `MIG-006` | medium | `javax.annotation` import — CDI annotations changed |
|
|
613
|
+
| `MIG-006` | medium¹ | `javax.annotation` import — CDI annotations changed (¹`javax.annotation.Generated` in autogenerated code → **low**, bucketed `generated`; explanation names the actual symbol) |
|
|
614
614
|
| `MIG-007` | medium | `javax.inject` import — DI annotations changed |
|
|
615
615
|
| `MIG-008` | medium | `javax.ws.rs` import — JAX-RS changed |
|
|
616
616
|
| `MIG-009` | medium | `javax.jms` import — JMS API changed |
|
|
@@ -722,9 +722,39 @@ reported as **N/A** (`score: null`), never as `0`. The top-level
|
|
|
722
722
|
states that `readiness_score` is a derived aggregate over applicable dimensions
|
|
723
723
|
only — for decisions, read the per-dimension breakdown + `blocking_count`.
|
|
724
724
|
|
|
725
|
+
#### Reliability guarantees (no version, no verdict)
|
|
726
|
+
|
|
727
|
+
A migration verdict shown to a decision-maker must never contradict its own
|
|
728
|
+
evidence. `migrate-check` enforces:
|
|
729
|
+
|
|
730
|
+
- **Version-gated framework axes.** The Hibernate 5→6 axis applies only when the
|
|
731
|
+
effective Hibernate version (resolved from `pom.xml`/Gradle, following Maven
|
|
732
|
+
`${properties}` and BOM-managed `<hibernate*.version>`) is `< 6`. A resolved
|
|
733
|
+
Hibernate **6+** repo is reported `migration_applicable: false` (N/A) — no
|
|
734
|
+
`hibernate_rewrite` headline. An **unresolved** version degrades to a
|
|
735
|
+
low-confidence hypothesis with no headline blocker. See
|
|
736
|
+
`hibernate.effective_version` / `version_major` / `version_confidence`.
|
|
737
|
+
- **Boot3 auto-disables without Spring.** `boot3.applicable` tracks real Spring
|
|
738
|
+
usage; Quarkus / Micronaut / Helidon / Jakarta-pure repos report `boot3` as N/A
|
|
739
|
+
(`spring_present: false`), not a contradictory `applicable: true`.
|
|
740
|
+
- **Permanent `javax.*` are never jakarta debt.** JDK/JSR namespaces
|
|
741
|
+
(`javax.xml.*`, `javax.crypto.*`, `javax.naming.*`, `javax.sql.*`,
|
|
742
|
+
`javax.management.*`, `javax.security.auth.*`, …) are allowlisted across every
|
|
743
|
+
jakarta scorer.
|
|
744
|
+
- **Three buckets: blocker ≠ hygiene ≠ test.** Only product (`main`) code counts
|
|
745
|
+
toward `blocking_count`, readiness, and effort. Test harnesses
|
|
746
|
+
(`testsuite/`, `test-framework/`, `integration-arquillian/`, `*-test*`,
|
|
747
|
+
`src/test/`) and autogenerated sources are tagged `code_context` and surfaced in
|
|
748
|
+
`non_blocking{}`. Best-practice hygiene (`java.util.Date`) is reported as
|
|
749
|
+
`hygiene_findings` and never sinks a dimension. Each finding carries
|
|
750
|
+
`code_context: main | test | generated`.
|
|
751
|
+
|
|
725
752
|
```bash
|
|
726
753
|
# inspect only the Hibernate rewrite targets
|
|
727
754
|
sourcecode migrate-check . --format json | jq '.hibernate.rewrite_targets[]'
|
|
755
|
+
|
|
756
|
+
# product blockers only (excludes test/fixtures + hygiene)
|
|
757
|
+
sourcecode migrate-check . --format json | jq '.blocking_count, .non_blocking, .hygiene_findings'
|
|
728
758
|
```
|
|
729
759
|
|
|
730
760
|
### `rename-class` — Java class rename
|
|
@@ -373,7 +373,7 @@ Emits **structured, tool-agnostic** codebase views as plain JSON/YAML — the ki
|
|
|
373
373
|
|------|--------|
|
|
374
374
|
| `--by-directory` | One group per source directory, each symbol with a `source_file:line` reference. |
|
|
375
375
|
| `--module-graph` | `{nodes, edges, summary}` — directories as modules, inter-module dependencies rolled up from class-level relation edges with hit counts + edge types. |
|
|
376
|
-
| `--integrations` | Outbound integrations (`RestTemplate`, `WebClient`, `@FeignClient`, `LdapTemplate`, `
|
|
376
|
+
| `--integrations` | Outbound integrations across Spring **and** plain-Java/Jakarta stacks: HTTP (`RestTemplate`, `WebClient`, `@FeignClient`, JDK `HttpClient`, Apache, OkHttp), LDAP (`LdapTemplate`, JNDI `InitialDirContext`/`LdapContext`), SMTP (`JavaMailSender`, JavaMail `Transport`/`MimeMessage`), and JMS — with `file:line` evidence and a literal `target` when present. Emits an explicit `confidence` (`observed` / `not_analyzed`) + `coverage_note`: a count of `0` means "no client construct found", **not** "no integrations" (runtime/DI-wired clients are not statically visible). |
|
|
377
377
|
| `--c4` | Unified document: `c4.{context, containers, components, code}` + `api_surface` + a `manifest` with per-directory content hashes for **incremental** consumers (skip directories whose hash is unchanged). `components.module_roots` rolls leaf source dirs up to architectural module roots and classifies each `layered` (DDD: ≥2 of `domain`/`application`/`infrastructure`) vs `flat` (legacy/flat package), with a verifiable `module_count` — so a consumer enumerates real modules instead of inferring boundaries from leaf directories. |
|
|
378
378
|
|
|
379
379
|
The section flags compose (pass several for one multi-section document); `--c4` assembles the full export on its own. URLs assembled at runtime yield `target: null` (honest absence, never a guess); containers are derived from build files (Maven/Gradle) and reported as a limitation when none are found.
|
|
@@ -572,7 +572,7 @@ Detects migration blockers across Java source files, Spring XML config files, an
|
|
|
572
572
|
| `MIG-002` | high | `javax.servlet` import — Servlet API changed |
|
|
573
573
|
| `MIG-003` | high | `javax.validation` import — Bean Validation changed |
|
|
574
574
|
| `MIG-004` | high | `javax.transaction` import — TX API changed |
|
|
575
|
-
| `MIG-006` | medium | `javax.annotation` import — CDI annotations changed |
|
|
575
|
+
| `MIG-006` | medium¹ | `javax.annotation` import — CDI annotations changed (¹`javax.annotation.Generated` in autogenerated code → **low**, bucketed `generated`; explanation names the actual symbol) |
|
|
576
576
|
| `MIG-007` | medium | `javax.inject` import — DI annotations changed |
|
|
577
577
|
| `MIG-008` | medium | `javax.ws.rs` import — JAX-RS changed |
|
|
578
578
|
| `MIG-009` | medium | `javax.jms` import — JMS API changed |
|
|
@@ -684,9 +684,39 @@ reported as **N/A** (`score: null`), never as `0`. The top-level
|
|
|
684
684
|
states that `readiness_score` is a derived aggregate over applicable dimensions
|
|
685
685
|
only — for decisions, read the per-dimension breakdown + `blocking_count`.
|
|
686
686
|
|
|
687
|
+
#### Reliability guarantees (no version, no verdict)
|
|
688
|
+
|
|
689
|
+
A migration verdict shown to a decision-maker must never contradict its own
|
|
690
|
+
evidence. `migrate-check` enforces:
|
|
691
|
+
|
|
692
|
+
- **Version-gated framework axes.** The Hibernate 5→6 axis applies only when the
|
|
693
|
+
effective Hibernate version (resolved from `pom.xml`/Gradle, following Maven
|
|
694
|
+
`${properties}` and BOM-managed `<hibernate*.version>`) is `< 6`. A resolved
|
|
695
|
+
Hibernate **6+** repo is reported `migration_applicable: false` (N/A) — no
|
|
696
|
+
`hibernate_rewrite` headline. An **unresolved** version degrades to a
|
|
697
|
+
low-confidence hypothesis with no headline blocker. See
|
|
698
|
+
`hibernate.effective_version` / `version_major` / `version_confidence`.
|
|
699
|
+
- **Boot3 auto-disables without Spring.** `boot3.applicable` tracks real Spring
|
|
700
|
+
usage; Quarkus / Micronaut / Helidon / Jakarta-pure repos report `boot3` as N/A
|
|
701
|
+
(`spring_present: false`), not a contradictory `applicable: true`.
|
|
702
|
+
- **Permanent `javax.*` are never jakarta debt.** JDK/JSR namespaces
|
|
703
|
+
(`javax.xml.*`, `javax.crypto.*`, `javax.naming.*`, `javax.sql.*`,
|
|
704
|
+
`javax.management.*`, `javax.security.auth.*`, …) are allowlisted across every
|
|
705
|
+
jakarta scorer.
|
|
706
|
+
- **Three buckets: blocker ≠ hygiene ≠ test.** Only product (`main`) code counts
|
|
707
|
+
toward `blocking_count`, readiness, and effort. Test harnesses
|
|
708
|
+
(`testsuite/`, `test-framework/`, `integration-arquillian/`, `*-test*`,
|
|
709
|
+
`src/test/`) and autogenerated sources are tagged `code_context` and surfaced in
|
|
710
|
+
`non_blocking{}`. Best-practice hygiene (`java.util.Date`) is reported as
|
|
711
|
+
`hygiene_findings` and never sinks a dimension. Each finding carries
|
|
712
|
+
`code_context: main | test | generated`.
|
|
713
|
+
|
|
687
714
|
```bash
|
|
688
715
|
# inspect only the Hibernate rewrite targets
|
|
689
716
|
sourcecode migrate-check . --format json | jq '.hibernate.rewrite_targets[]'
|
|
717
|
+
|
|
718
|
+
# product blockers only (excludes test/fixtures + hygiene)
|
|
719
|
+
sourcecode migrate-check . --format json | jq '.blocking_count, .non_blocking, .hygiene_findings'
|
|
690
720
|
```
|
|
691
721
|
|
|
692
722
|
### `rename-class` — Java class rename
|
|
@@ -253,6 +253,75 @@ def _scan_build_dependency(root: Path) -> tuple[bool, list[str]]:
|
|
|
253
253
|
samples.append(snippet)
|
|
254
254
|
return found, samples
|
|
255
255
|
|
|
256
|
+
|
|
257
|
+
# ── BUG #1: effective Hibernate version resolution ─────────────────────────
|
|
258
|
+
# A 5→6 rewrite verdict is only valid when the project is actually on Hibernate 5.
|
|
259
|
+
# Resolve the effective major version from build descriptors, following Maven
|
|
260
|
+
# ${properties} (incl. BOM-managed values declared as <hibernate*.version>) and
|
|
261
|
+
# explicit hibernate-core / hibernate-orm coordinates. When the resolved major is
|
|
262
|
+
# ≥ 6 the 5→6 axis does NOT apply (the migration is already done). When it cannot
|
|
263
|
+
# be resolved the axis degrades to a low-confidence hypothesis (no headline).
|
|
264
|
+
_HIB_VER = r"(\d+\.\d+(?:\.\d+)?(?:[.\-][\w]+)*)" # 6.2.13.Final, 5.6.15, 6.2
|
|
265
|
+
_HIB_PROP_RE = re.compile(
|
|
266
|
+
r"<((?:[\w.\-]*hibernate[\w.\-]*?)\.?version)>\s*" + _HIB_VER + r"\s*</\1>",
|
|
267
|
+
re.IGNORECASE,
|
|
268
|
+
)
|
|
269
|
+
_HIB_COORD_VERSION_RE = re.compile(
|
|
270
|
+
r"<artifactId>\s*hibernate-(?:core|orm)\s*</artifactId>\s*"
|
|
271
|
+
r"(?:<[^>]+>[^<]*</[^>]+>\s*)*?<version>\s*" + _HIB_VER,
|
|
272
|
+
re.IGNORECASE | re.DOTALL,
|
|
273
|
+
)
|
|
274
|
+
_HIB_GRADLE_VERSION_RE = re.compile(
|
|
275
|
+
r"org\.hibernate(?:\.orm)?:hibernate-(?:core|orm):" + _HIB_VER,
|
|
276
|
+
re.IGNORECASE,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _ver_key(full: str) -> tuple[int, int]:
|
|
281
|
+
parts = full.split(".")
|
|
282
|
+
try:
|
|
283
|
+
major = int(parts[0])
|
|
284
|
+
except (ValueError, IndexError):
|
|
285
|
+
return (0, 0)
|
|
286
|
+
try:
|
|
287
|
+
minor = int(parts[1]) if len(parts) > 1 else 0
|
|
288
|
+
except ValueError:
|
|
289
|
+
minor = 0
|
|
290
|
+
return (major, minor)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _resolve_hibernate_version(root: Path) -> tuple[Optional[str], Optional[int], str]:
|
|
294
|
+
"""Return (full_version_string, major, confidence) for the effective Hibernate.
|
|
295
|
+
|
|
296
|
+
confidence is "high" when a version was resolved from a build descriptor,
|
|
297
|
+
"none" when none could be determined (degrade to hypothesis). The newest
|
|
298
|
+
declared Hibernate wins in a multi-module build.
|
|
299
|
+
"""
|
|
300
|
+
import os
|
|
301
|
+
best_full: Optional[str] = None
|
|
302
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
303
|
+
dirnames[:] = [d for d in dirnames if d not in _SKIP_BUILD_SCAN_DIRS]
|
|
304
|
+
for fname in filenames:
|
|
305
|
+
if fname not in _BUILD_FILE_NAMES:
|
|
306
|
+
continue
|
|
307
|
+
try:
|
|
308
|
+
text = (Path(dirpath) / fname).read_text(encoding="utf-8", errors="replace")
|
|
309
|
+
except OSError:
|
|
310
|
+
continue
|
|
311
|
+
fulls: list[str] = []
|
|
312
|
+
for m in _HIB_PROP_RE.finditer(text):
|
|
313
|
+
fulls.append(m.group(2))
|
|
314
|
+
for m in _HIB_COORD_VERSION_RE.finditer(text):
|
|
315
|
+
fulls.append(m.group(1))
|
|
316
|
+
for m in _HIB_GRADLE_VERSION_RE.finditer(text):
|
|
317
|
+
fulls.append(m.group(1))
|
|
318
|
+
for full in fulls:
|
|
319
|
+
if best_full is None or _ver_key(full) > _ver_key(best_full):
|
|
320
|
+
best_full = full
|
|
321
|
+
if best_full is None:
|
|
322
|
+
return None, None, "none"
|
|
323
|
+
return best_full, _ver_key(best_full)[0], "high"
|
|
324
|
+
|
|
256
325
|
# Escalation markers — dynamic / reflection-based persistence construction.
|
|
257
326
|
_ABSTRACTION_CLASS_RE = re.compile(
|
|
258
327
|
r"\b(DynamicEntityDao|DynamicEntityDaoImpl|BasicPersistenceModule|"
|
|
@@ -406,12 +475,23 @@ class HibernateStratification:
|
|
|
406
475
|
# when backed by a build dependency or a parsed org.hibernate import, "none"
|
|
407
476
|
# when detection was vetoed for lack of evidence.
|
|
408
477
|
evidence: dict = field(default_factory=dict)
|
|
478
|
+
# BUG #1: effective Hibernate version + whether the 5→6 axis applies at all.
|
|
479
|
+
# When the resolved major is ≥ 6 the migration is already done → not applicable
|
|
480
|
+
# (never a blocker). When unresolved, the axis is a low-confidence hypothesis.
|
|
481
|
+
effective_version: Optional[str] = None
|
|
482
|
+
version_major: Optional[int] = None
|
|
483
|
+
version_confidence: str = "none"
|
|
484
|
+
migration_applicable: bool = True
|
|
409
485
|
|
|
410
486
|
def to_dict(self) -> dict:
|
|
411
487
|
return {
|
|
412
488
|
"schema_version": HIBERNATE_SCHEMA_VERSION,
|
|
413
489
|
"detected": self.detected,
|
|
414
490
|
"evidence": self.evidence,
|
|
491
|
+
"effective_version": self.effective_version,
|
|
492
|
+
"version_major": self.version_major,
|
|
493
|
+
"version_confidence": self.version_confidence,
|
|
494
|
+
"migration_applicable": self.migration_applicable,
|
|
415
495
|
"classification": self.classification,
|
|
416
496
|
"classification_label": self.classification_label,
|
|
417
497
|
"stratified": True,
|
|
@@ -763,6 +843,7 @@ def analyze_hibernate(file_paths: list[str], root: Path) -> HibernateStratificat
|
|
|
763
843
|
return strat
|
|
764
844
|
|
|
765
845
|
dep_present, dep_samples = _scan_build_dependency(root)
|
|
846
|
+
eff_version, version_major, version_conf = _resolve_hibernate_version(root)
|
|
766
847
|
|
|
767
848
|
has_evidence = dep_present or any_hibernate_import or any_jpa_import
|
|
768
849
|
evidence: dict = {
|
|
@@ -771,6 +852,9 @@ def analyze_hibernate(file_paths: list[str], root: Path) -> HibernateStratificat
|
|
|
771
852
|
"hibernate_import_present": any_hibernate_import,
|
|
772
853
|
"hibernate_import_sample": hibernate_import_sample,
|
|
773
854
|
"jpa_import_present": any_jpa_import,
|
|
855
|
+
"effective_version": eff_version,
|
|
856
|
+
"version_major": version_major,
|
|
857
|
+
"version_confidence": version_conf,
|
|
774
858
|
"confidence": "high" if has_evidence else "none",
|
|
775
859
|
}
|
|
776
860
|
|
|
@@ -959,6 +1043,12 @@ def analyze_hibernate(file_paths: list[str], root: Path) -> HibernateStratificat
|
|
|
959
1043
|
strat = HibernateStratification()
|
|
960
1044
|
strat.findings = findings
|
|
961
1045
|
strat.evidence = evidence
|
|
1046
|
+
strat.effective_version = eff_version
|
|
1047
|
+
strat.version_major = version_major
|
|
1048
|
+
strat.version_confidence = version_conf
|
|
1049
|
+
# BUG #1: the 5→6 axis only applies when NOT already on Hibernate 6+. A
|
|
1050
|
+
# resolved major ≥ 6 means the migration is complete — never a blocker.
|
|
1051
|
+
strat.migration_applicable = not (version_major is not None and version_major >= 6)
|
|
962
1052
|
strat.rewrite_targets = sorted(
|
|
963
1053
|
targets, key=lambda t: (t.source_file, t.line_start, t.layer, t.id)
|
|
964
1054
|
)
|
|
@@ -1126,13 +1216,23 @@ def analyze_hibernate(file_paths: list[str], root: Path) -> HibernateStratificat
|
|
|
1126
1216
|
stops.append("SQL/HQL shape not statically inferable (string concatenation)")
|
|
1127
1217
|
strat.stop_conditions_triggered = stops
|
|
1128
1218
|
|
|
1129
|
-
if
|
|
1219
|
+
if not strat.migration_applicable:
|
|
1220
|
+
# Already on Hibernate 6+ — the 5→6 stratification below is retained as an
|
|
1221
|
+
# informational exposure map, but it is NOT a migration and NOT a blocker.
|
|
1222
|
+
strat.classification = CLASS_NONE
|
|
1223
|
+
strat.classification_label = (
|
|
1224
|
+
f"ALREADY ON HIBERNATE {strat.version_major} "
|
|
1225
|
+
f"({strat.effective_version}) — NO 5→6 MIGRATION PENDING"
|
|
1226
|
+
)
|
|
1227
|
+
strat.stop_conditions_triggered = []
|
|
1228
|
+
elif stops:
|
|
1130
1229
|
strat.classification = CLASS_REWRITE
|
|
1131
1230
|
elif layer_files[LAYER_CRITERIA] or concat_query_global or jpa_deprecated_seen:
|
|
1132
1231
|
strat.classification = CLASS_UPGRADE_CARE
|
|
1133
1232
|
else:
|
|
1134
1233
|
strat.classification = CLASS_UPGRADE
|
|
1135
|
-
|
|
1234
|
+
if strat.migration_applicable:
|
|
1235
|
+
strat.classification_label = _CLASS_LABELS[strat.classification]
|
|
1136
1236
|
|
|
1137
1237
|
# ── Risk separation: observable vs inferred ─────────────────────────────
|
|
1138
1238
|
observable: list[str] = []
|
|
@@ -35,10 +35,28 @@ _ATTR_NAME_RE = re.compile(r'(?:name|value)\s*=\s*"([^"]*)"')
|
|
|
35
35
|
_FIRST_LITERAL_RE = re.compile(r'^\s*"([^"]*)"')
|
|
36
36
|
|
|
37
37
|
# token -> (kind, client). Matched as whole-word usage outside imports/comments.
|
|
38
|
+
# Covers Spring AND plain-Java/Jakarta stacks (Quarkus, Micronaut, Keycloak SPI):
|
|
39
|
+
# the detector must not be Spring-centric, or a non-Spring repo with real LDAP /
|
|
40
|
+
# SMTP / HTTP integrations falsely reports "0 integrations".
|
|
38
41
|
_TOKEN_CLIENTS: "tuple[tuple[str, str, str], ...]" = (
|
|
42
|
+
# Spring HTTP clients
|
|
39
43
|
("RestTemplate", "http", "resttemplate"),
|
|
40
44
|
("WebClient", "http", "webclient"),
|
|
45
|
+
# Plain-Java / third-party HTTP clients
|
|
46
|
+
("HttpClient", "http", "jdk-httpclient"), # java.net.http.HttpClient
|
|
47
|
+
("CloseableHttpClient", "http", "apache-httpclient"),
|
|
48
|
+
("HttpClients", "http", "apache-httpclient"),
|
|
49
|
+
("OkHttpClient", "http", "okhttp"),
|
|
50
|
+
# LDAP / directory (Spring + JNDI)
|
|
41
51
|
("LdapTemplate", "ldap", "ldaptemplate"),
|
|
52
|
+
("InitialLdapContext", "ldap", "jndi-ldap"),
|
|
53
|
+
("InitialDirContext", "ldap", "jndi-ldap"),
|
|
54
|
+
("LdapContext", "ldap", "jndi-ldap"),
|
|
55
|
+
# Mail / SMTP (JavaMail / Jakarta Mail)
|
|
56
|
+
("JavaMailSender", "smtp", "spring-mail"),
|
|
57
|
+
("MimeMessage", "smtp", "javamail"),
|
|
58
|
+
("Transport", "smtp", "javamail"),
|
|
59
|
+
# JMS / messaging
|
|
42
60
|
("JmsTemplate", "jms", "jmstemplate"),
|
|
43
61
|
("ActiveMQConnectionFactory", "jms", "activemq"),
|
|
44
62
|
)
|
|
@@ -156,8 +174,21 @@ def detect_integrations(file_paths: "list[str]", root: Path) -> dict:
|
|
|
156
174
|
for r in records:
|
|
157
175
|
by_kind[r["kind"]] = by_kind.get(r["kind"], 0) + 1
|
|
158
176
|
|
|
177
|
+
# BUG #9: honest confidence. A zero count means "no detectable client
|
|
178
|
+
# construct was found", NOT "this system has no integrations" — runtime-wired
|
|
179
|
+
# clients (DI, config-driven endpoints, JCA connectors) are invisible to static
|
|
180
|
+
# text matching. Report that explicitly instead of an authoritative "0".
|
|
181
|
+
confidence = "observed" if records else "not_analyzed"
|
|
159
182
|
return {
|
|
160
183
|
"integrations": records,
|
|
161
184
|
"by_kind": {k: by_kind[k] for k in sorted(by_kind)},
|
|
162
185
|
"count": len(records),
|
|
186
|
+
"confidence": confidence,
|
|
187
|
+
"coverage_note": (
|
|
188
|
+
"Detects HTTP (RestTemplate/WebClient/JDK/Apache/OkHttp), LDAP (Spring "
|
|
189
|
+
"+ JNDI), SMTP (JavaMail), and JMS client constructs by source-text "
|
|
190
|
+
"matching. A count of 0 means no such construct was found, not that the "
|
|
191
|
+
"system has no outbound integrations — runtime/DI-wired clients are not "
|
|
192
|
+
"statically visible."
|
|
193
|
+
),
|
|
163
194
|
}
|