sourcecode 1.39.0__tar.gz → 1.42.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.
Files changed (122) hide show
  1. {sourcecode-1.39.0 → sourcecode-1.42.0}/.gitignore +4 -1
  2. sourcecode-1.42.0/CHANGELOG.md +157 -0
  3. {sourcecode-1.39.0 → sourcecode-1.42.0}/PKG-INFO +1 -1
  4. {sourcecode-1.39.0 → sourcecode-1.42.0}/pyproject.toml +1 -1
  5. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/cir_graphs.py +72 -7
  7. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/repository_ir.py +324 -88
  8. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_impact.py +102 -12
  9. sourcecode-1.39.0/CHANGELOG.md +0 -54
  10. sourcecode-1.39.0/supabase/.temp/cli-latest +0 -1
  11. {sourcecode-1.39.0 → sourcecode-1.42.0}/.github/workflows/build-windows.yml +0 -0
  12. {sourcecode-1.39.0 → sourcecode-1.42.0}/.ruff.toml +0 -0
  13. {sourcecode-1.39.0 → sourcecode-1.42.0}/CONTRIBUTING.md +0 -0
  14. {sourcecode-1.39.0 → sourcecode-1.42.0}/LICENSE +0 -0
  15. {sourcecode-1.39.0 → sourcecode-1.42.0}/README.md +0 -0
  16. {sourcecode-1.39.0 → sourcecode-1.42.0}/SECURITY.md +0 -0
  17. {sourcecode-1.39.0 → sourcecode-1.42.0}/raw +0 -0
  18. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/adaptive_scanner.py +0 -0
  19. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/architecture_analyzer.py +0 -0
  20. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/architecture_summary.py +0 -0
  21. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/ast_extractor.py +0 -0
  22. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/cache.py +0 -0
  23. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/canonical_ir.py +0 -0
  24. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/classifier.py +0 -0
  25. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/cli.py +0 -0
  26. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  27. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/confidence_analyzer.py +0 -0
  28. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/context_scorer.py +0 -0
  29. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/context_summarizer.py +0 -0
  30. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/contract_model.py +0 -0
  31. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/contract_pipeline.py +0 -0
  32. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/coverage_parser.py +0 -0
  33. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/dependency_analyzer.py +0 -0
  34. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/__init__.py +0 -0
  35. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/base.py +0 -0
  36. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  37. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/dart.py +0 -0
  38. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/dotnet.py +0 -0
  39. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/elixir.py +0 -0
  40. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/go.py +0 -0
  41. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/heuristic.py +0 -0
  42. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/hybrid.py +0 -0
  43. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/java.py +0 -0
  44. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  45. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/nodejs.py +0 -0
  46. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/parsers.py +0 -0
  47. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/php.py +0 -0
  48. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/project.py +0 -0
  49. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/python.py +0 -0
  50. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/ruby.py +0 -0
  51. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/rust.py +0 -0
  52. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/systems.py +0 -0
  53. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/terraform.py +0 -0
  54. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/detectors/tooling.py +0 -0
  55. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/doc_analyzer.py +0 -0
  56. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  57. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/env_analyzer.py +0 -0
  58. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/error_schema.py +0 -0
  59. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/explain.py +0 -0
  60. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/file_chunker.py +0 -0
  61. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/file_classifier.py +0 -0
  62. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/flow_analyzer.py +0 -0
  63. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/format_contract.py +0 -0
  64. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/fqn_utils.py +0 -0
  65. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/git_analyzer.py +0 -0
  66. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/graph_analyzer.py +0 -0
  67. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/license.py +0 -0
  68. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/__init__.py +0 -0
  69. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  70. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  71. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  72. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  73. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  74. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  75. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/registry.py +0 -0
  76. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/runner.py +0 -0
  77. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp/server.py +0 -0
  78. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/mcp_nudge.py +0 -0
  79. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/metrics_analyzer.py +0 -0
  80. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/migrate_check.py +0 -0
  81. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/openapi_surface.py +0 -0
  82. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/output_budget.py +0 -0
  83. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/path_filters.py +0 -0
  84. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  85. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/pr_impact.py +0 -0
  86. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/prepare_context.py +0 -0
  87. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/progress.py +0 -0
  88. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/ranking_engine.py +0 -0
  89. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/redactor.py +0 -0
  90. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/relevance_scorer.py +0 -0
  91. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/rename_refactor.py +0 -0
  92. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/repo_classifier.py +0 -0
  93. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/ris.py +0 -0
  94. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/runtime_classifier.py +0 -0
  95. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/scanner.py +0 -0
  96. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/schema.py +0 -0
  97. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/security_config.py +0 -0
  98. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/semantic_analyzer.py +0 -0
  99. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/serializer.py +0 -0
  100. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_event_topology.py +0 -0
  101. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_findings.py +0 -0
  102. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_model.py +0 -0
  103. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_security_audit.py +0 -0
  104. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_semantic.py +0 -0
  105. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  106. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/summarizer.py +0 -0
  107. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/telemetry/__init__.py +0 -0
  108. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/telemetry/config.py +0 -0
  109. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/telemetry/consent.py +0 -0
  110. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/telemetry/events.py +0 -0
  111. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/telemetry/filters.py +0 -0
  112. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/telemetry/transport.py +0 -0
  113. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/tree_utils.py +0 -0
  114. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/validation_surface.py +0 -0
  115. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/version_check.py +0 -0
  116. {sourcecode-1.39.0 → sourcecode-1.42.0}/src/sourcecode/workspace.py +0 -0
  117. {sourcecode-1.39.0 → sourcecode-1.42.0}/supabase/functions/README.md +0 -0
  118. {sourcecode-1.39.0 → sourcecode-1.42.0}/supabase/functions/get-license/index.ts +0 -0
  119. {sourcecode-1.39.0 → sourcecode-1.42.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  120. {sourcecode-1.39.0 → sourcecode-1.42.0}/supabase/functions/telemetry/index.ts +0 -0
  121. {sourcecode-1.39.0 → sourcecode-1.42.0}/supabase/sql/license_event_ordering.sql +0 -0
  122. {sourcecode-1.39.0 → sourcecode-1.42.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -33,4 +33,7 @@ src/*.egg-info/
33
33
  .DS_Store
34
34
  Thumbs.db
35
35
 
36
- .planning
36
+ .planning
37
+
38
+ # Supabase local temp
39
+ supabase/.temp/
@@ -0,0 +1,157 @@
1
+ # Changelog
2
+
3
+ ## [1.42.0] — 2026-06-16
4
+
5
+ ### Added
6
+ - **Fase 22 — type-usage edges in `impact-chain` (CH-003).** Value/DTO/response
7
+ types previously had an invisible blast radius: the impact graph modelled call and
8
+ DI/injection edges but not how a type is wired *by type*. Two new edges close this:
9
+ - **`returns`** — `method → returnTypeFQN` (method-level). For a `@ResponseBody`
10
+ handler returning a domain type this is the only link from the type back to its
11
+ endpoint, so `_collect_endpoints` now surfaces that route precisely.
12
+ - **`instantiates`** — `class → T` for `new T(...)`, giving build-only value types
13
+ (commands, receipts) a visible blast radius. Controller-like classes are excluded
14
+ (already covered precisely by `returns`) to avoid broadening a DTO's impact to
15
+ every route on the controller.
16
+
17
+ ### Fixed
18
+ - **Inline-annotation method parsing.** `_METHOD_DECL_RE` could not match a
19
+ modifier-position annotation (`public @ResponseBody Vets foo()`); the whole
20
+ declaration failed and the method — its endpoint *and* return type — was silently
21
+ dropped. Inline annotations are now consumed and folded into the method's annotation
22
+ set. Recovers, e.g., the `GET /vets` handler in spring-petclinic `VetController`.
23
+
24
+ ### Changed
25
+ - **Safety guard for type-usage blind spots (CH-003 Part 1).** A fully empty blast
26
+ radius on a positively-identified plain value type (node present, `symbol_kind` in
27
+ class/enum/record, no stereotype annotation, role `other`, not a controller) is no
28
+ longer reported at `confidence: high` — it drops to `low` with a warning that an
29
+ empty result is not proof the type is unused. Spine symbols and incomplete-IR cases
30
+ keep prior behaviour. The guard now stays dormant when real type-usage edges exist.
31
+
32
+ ### Field test (spring-petclinic #2333)
33
+ - `impact-chain Vets`: was `confidence: high` with 0 callers / 0 endpoints (a dangerous
34
+ false zero) → now `high`, caller `showResourcesVetList`, endpoint `GET /vets`.
35
+ - `impact-chain VetController`: was 1 of 2 endpoints → both (`GET /vets` + `/vets.html`).
36
+
37
+ ## [1.41.0] — 2026-06-16
38
+
39
+ ### Added
40
+ - **Fase 21 — spec-recovered HTTP routes reach `impact-chain`.** In
41
+ openapi-generator "interface-only" repos (`@RestController implements XxxApi`,
42
+ mappings on the generated interface under `target/generated-sources`), the HTTP
43
+ surface is recovered from the OpenAPI spec. That recovery previously lived only in
44
+ the `endpoints` command path, so `impact-chain` on a repository/service symbol
45
+ reported `endpoints_affected = 0` even though the route existed. The spec→controller
46
+ linking is now shared and wired through the impact model end to end.
47
+ - **21-02** — `_recover_openapi_spec_routes` (repository_ir): single shared helper that
48
+ links spec operations to interface-defined controllers and emits both the
49
+ `endpoints`-command shape and the `route_surface` shape. `build_repo_ir` merges the
50
+ spec-sourced `route_surface` entries, so they flow `route_surface → CanonicalRepositoryIR
51
+ → EndpointIndex → impact-chain`. The `endpoints` command output stays byte-identical.
52
+ - **21-03** — `impact-chain` BFS now crosses the interface DI boundary mid-chain.
53
+ `_bfs_callers` takes the `ImplementationGraph` and, for each implementation class it
54
+ reaches, folds in the reverse edges of that class's interfaces (callers inject the
55
+ interface type, so the `injects` edges sit on the interface node). Closes
56
+ `repo → serviceImpl → (service interface) → controller` so the spec-recovered endpoint
57
+ surfaces. CH-001b already did this for the seed; 21-03 extends it to every impl in the
58
+ traversal.
59
+
60
+ ### Fixed
61
+ - **BUG-PARSER-002 — multi-line constructor/method signatures.** A signature whose
62
+ parameter list spans several physical lines (the canonical Spring constructor-injection
63
+ idiom, one param per line) lost its parameters: the per-line decl regex captured `[^)]*`
64
+ up to end-of-line only, so `param_types` was empty and no `injects` edges were emitted.
65
+ The pre-join pass now balances parentheses for declaration openers, mirroring the
66
+ existing multi-line class-declaration join.
67
+ - **BUG-PARSER-003 — wildcard-import dependency resolution.** A dependency type pulled in
68
+ via `import pkg.*` was never resolved to an FQN (`import_map` skips `.*`), so even a
69
+ single-line constructor produced no `injects` edge. `_build_relations` now receives the
70
+ global `{package → {simple → FQN}}` map and resolves wildcard-imported types against it.
71
+
72
+ ### Why
73
+ Field test of spring-petclinic-rest issue #11 (weakness #2): `impact-chain` on a repo or
74
+ service symbol surfaced no affected HTTP endpoints in interface-only openapi-generator
75
+ repos, even though the `endpoints` command listed the routes. The break was structural at
76
+ several layers — the spec→controller linking never reached `route_surface`/the CIR, the DI
77
+ chain dead-ended at the service impl, and (the live-repo blocker) the very first hop
78
+ repo→service was missing because petclinic's `ClinicServiceImpl` uses a multi-line
79
+ constructor with a wildcard repository import. With all four fixes, the live E2E
80
+ `impact-chain VetRepository` on petclinic-rest goes from **0** affected endpoints to the
81
+ full transitive set (**35**, reaching every controller incl. the spec-recovered v2 routes).
82
+
83
+ ## [1.40.0] — 2026-06-16
84
+
85
+ ### Added
86
+ - **CH-001c — interface impact models implementors.** `impact-chain` over an
87
+ interface or abstract base now resolves its full in-repo descendant set:
88
+ concrete `implements` classes, `extends` sub-interfaces, and subclasses, traversed
89
+ transitively. A base interface query reaches impls hidden behind an intermediate
90
+ sub-interface (e.g. Spring Data repositories: `SpringDataVetRepository extends
91
+ VetRepository` alongside the JPA/JDBC impls).
92
+ - `ImplementationGraph` gains `subtypes_of()`, `supertypes_of()`, and
93
+ `all_subtypes_of()` (transitive, cycle-safe). `extends` edges are now captured;
94
+ `implements`-only indices (`implementations_of`/`primary_implementation`) keep their
95
+ strict DI-resolution semantics — sub-interfaces are not counted as bean implementations.
96
+ - `ImpactChainResult.implementations`: new output field listing the in-repo subtypes
97
+ of the queried type, making the implementation blast radius visible (previously the
98
+ impls were silent BFS seeds).
99
+
100
+ ### Why
101
+ Field test of spring-petclinic-rest issue #11 surfaced the gap: `impact-chain
102
+ VetRepository` returned only the SpringData sub-interface, missing the JPA/JDBC impls —
103
+ exactly the "3 impls" graph the maintainer cared about. Interface impact did not model
104
+ implementors.
105
+
106
+ ## [1.33.0] — 2026-05-29
107
+
108
+ ### Changed
109
+ - **Repositioned product identity** around persistent structural cache and ultra-fast repeated analysis for AI coding agents. Cache is now the central product story, not a performance feature.
110
+ - README rewritten: new intro emphasizing persistent context engine, cache performance benchmarks promoted above quickstart, agent workflow patterns section added, "Java/Spring analysis CLI" framing moved down.
111
+ - `pyproject.toml` description updated: "Persistent structural context and ultra-fast repeated analysis for AI coding agents".
112
+ - CLI `--help` updated: tagline, cold/warm latency numbers, cache commands section added prominently.
113
+
114
+ ## [Unreleased]
115
+
116
+ ### Added
117
+ - `prepare-context generate-tests --include-config`: opt-in flag to include tooling
118
+ config files (`.eslintrc*`, `karma.conf.js`, `jest.config.js`, etc.) in `test_gaps`.
119
+ By default these are now excluded (IMP-1).
120
+
121
+ ### Fixed
122
+ - **BUG-1** `repo-ir` stdout: JSON is now written via `stdout.buffer` (UTF-8) so Unicode
123
+ characters (e.g. `→`) survive on Windows consoles with non-UTF-8 codecs.
124
+ `main_entry` also calls `stdout.reconfigure(encoding='utf-8')` on startup.
125
+ - **BUG-2** `--exclude` with a space-separated value (`--exclude "a,b"`) was silently
126
+ consumed as the repository path. Added `--exclude` to the options-with-value registry
127
+ so its argument is parsed correctly.
128
+ - **BUG-3** `prepare-context onboard --fast` returned only the git-changed file
129
+ (e.g. `.idea/vcs.xml`). Fast mode for `onboard` now always uses a shallow depth-2
130
+ scan so manifests and entry points are reliably discovered.
131
+ - **BUG-4** `angular_version: null` when `package.json` has `"dependencies": null`.
132
+ The merge now uses `or {}` so an explicit `null` key doesn't raise TypeError.
133
+ Also checks `peerDependencies` as a fallback source.
134
+ - **BUG-5** `lazy_routes_count: 0` in Angular projects. Counting now uses
135
+ `loadChildren:` and `loadComponent:` (property syntax) instead of the defunct
136
+ `loadChildren(` call syntax.
137
+ - **BUG-6** Angular `*.component.ts` files classified as Spring `@Service` in
138
+ `review-pr` and `prepare-context` output on fullstack Java+Angular repos.
139
+ Root cause: `"component"` was in `_SERVICE_KW` inside `_classify_changed_file`.
140
+ Fix: Angular detection block (by `.ts` stem suffix) now runs **before** the
141
+ Java/Spring heuristics. `"component"` removed from `_SERVICE_KW`. Added
142
+ `ng_component`, `ng_pipe`, `ng_directive`, `ng_guard`, `ng_interceptor`,
143
+ `ng_resolver`, `ng_service`, `ng_module` to `_ARTIFACT_CHANGE_EFFECT`.
144
+ `ast_extractor._detect_role` updated with the same Angular stem-suffix map.
145
+ - **BUG-7** `--compact` help text referenced `--slim (when available)` which is
146
+ not implemented and does not exist as a CLI option, causing user confusion
147
+ (`Error: No such option '--slim'`). Removed the reference (Option A: remove
148
+ mention rather than implement the flag this sprint).
149
+
150
+ ### Regression tests added (`tests/test_bug_fixes_v13122.py`)
151
+ - 13 exit-code tests covering all commands reported as EXIT 255 — all verified
152
+ to return EXIT 0 (BUG-1 through BUG-7 of this audit cycle).
153
+ - 8 Angular classification tests locking `ng_component` / `ng_service` / `ng_*`
154
+ artifact types and `_ARTIFACT_CHANGE_EFFECT` entries.
155
+ - 3 `--slim` tests verifying the option is absent from help and CLI surface.
156
+ - 6 `angular_version` parsing tests covering `dependencies`, `devDependencies`,
157
+ `peerDependencies`, `null` JSON values, and version prefix stripping.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.39.0
3
+ Version: 1.42.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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.39.0"
7
+ version = "1.42.0"
8
8
  description = "Persistent structural context and ultra-fast repeated analysis for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.39.0"
3
+ __version__ = "1.42.0"
@@ -25,22 +25,67 @@ class ImplementationGraph:
25
25
 
26
26
  Built from implements edges where BOTH ends are known CIR symbols (internal
27
27
  interface/class pairs). External framework interfaces are excluded.
28
+
29
+ Subtype indices (CH-001c): `extends` edges are also captured so that
30
+ interface-to-interface inheritance (`SubIface extends BaseIface`) and abstract
31
+ base classes (`SubClass extends BaseClass`) are modeled as descendants of the
32
+ supertype. The `implements`-only indices (`_impl_of`/`_ifaces_of`) are kept
33
+ separate to preserve DI resolution semantics (primary_implementation).
28
34
  """
29
35
  _impl_of: dict[str, list[str]] = field(default_factory=dict)
30
36
  _ifaces_of: dict[str, list[str]] = field(default_factory=dict)
37
+ # CH-001c: union of implements + extends descendants (impl classes, sub-interfaces,
38
+ # subclasses) keyed by supertype FQN, and its reverse.
39
+ _subtype_of: dict[str, list[str]] = field(default_factory=dict)
40
+ _supertype_of: dict[str, list[str]] = field(default_factory=dict)
31
41
 
32
42
  # ---------------------------------------------------------------------------
33
43
  # Queries
34
44
  # ---------------------------------------------------------------------------
35
45
 
36
46
  def implementations_of(self, interface_fqn: str) -> list[str]:
37
- """Return FQNs of classes that implement interface_fqn (in-repo only)."""
47
+ """Return FQNs of classes that implement interface_fqn (in-repo only).
48
+
49
+ Strictly `implements` edges — excludes sub-interfaces/subclasses. Use
50
+ subtypes_of()/all_subtypes_of() for the full impact-relevant descendant set.
51
+ """
38
52
  return self._impl_of.get(interface_fqn, [])
39
53
 
40
54
  def interfaces_of(self, class_fqn: str) -> list[str]:
41
55
  """Return FQNs of in-repo interfaces implemented by class_fqn."""
42
56
  return self._ifaces_of.get(class_fqn, [])
43
57
 
58
+ def subtypes_of(self, type_fqn: str) -> list[str]:
59
+ """Return direct in-repo subtypes of type_fqn.
60
+
61
+ Union of `implements` (concrete impls) and `extends` (sub-interfaces,
62
+ subclasses) children. This is the impact-relevant descendant set: a change
63
+ to type_fqn's contract propagates to all of these.
64
+ """
65
+ return self._subtype_of.get(type_fqn, [])
66
+
67
+ def supertypes_of(self, type_fqn: str) -> list[str]:
68
+ """Return direct in-repo supertypes of type_fqn (implemented/extended)."""
69
+ return self._supertype_of.get(type_fqn, [])
70
+
71
+ def all_subtypes_of(self, type_fqn: str) -> list[str]:
72
+ """Return the transitive closure of in-repo subtypes (BFS, cycle-safe).
73
+
74
+ Covers multi-level hierarchies, e.g. a base interface → sub-interface →
75
+ concrete impl chain. Order is breadth-first from type_fqn; deduplicated.
76
+ """
77
+ seen: set[str] = set()
78
+ out: list[str] = []
79
+ queue: list[str] = list(self._subtype_of.get(type_fqn, []))
80
+ while queue:
81
+ sub = queue.pop(0)
82
+ if sub in seen:
83
+ continue
84
+ seen.add(sub)
85
+ out.append(sub)
86
+ queue.extend(self._subtype_of.get(sub, []))
87
+ return out
88
+
44
89
  def primary_implementation(self, interface_fqn: str) -> str | None:
45
90
  """Return the single implementation if unambiguous, else None.
46
91
 
@@ -89,9 +134,14 @@ class ImplementationGraph:
89
134
 
90
135
  impl_of: dict[str, list[str]] = {}
91
136
  ifaces_of: dict[str, list[str]] = {}
137
+ subtype_of: dict[str, list[str]] = {}
138
+ supertype_of: dict[str, list[str]] = {}
92
139
 
93
140
  for edge in dependencies:
94
- if edge.get("type") != "implements":
141
+ etype = edge.get("type")
142
+ # CH-001c: extends edges (sub-interface / subclass) are subtype relations
143
+ # too, even though they never feed the implements-only DI indices.
144
+ if etype not in ("implements", "extends"):
95
145
  continue
96
146
  from_fqn = (edge.get("from") or "").strip()
97
147
  to_fqn = (edge.get("to") or "").strip()
@@ -110,12 +160,27 @@ class ImplementationGraph:
110
160
  if ">" in from_fqn or "<" in from_fqn:
111
161
  continue
112
162
 
113
- if from_fqn not in impl_of.get(to_fqn, []):
114
- impl_of.setdefault(to_fqn, []).append(from_fqn)
115
- if to_fqn not in ifaces_of.get(from_fqn, []):
116
- ifaces_of.setdefault(from_fqn, []).append(to_fqn)
163
+ # Subtype indices both implements and extends contribute descendants.
164
+ if from_fqn not in subtype_of.get(to_fqn, []):
165
+ subtype_of.setdefault(to_fqn, []).append(from_fqn)
166
+ if to_fqn not in supertype_of.get(from_fqn, []):
167
+ supertype_of.setdefault(from_fqn, []).append(to_fqn)
168
+
169
+ # Implements-only indices — preserve DI resolution semantics. Sub-interfaces
170
+ # and subclasses (extends) must NOT count as "implementations" for
171
+ # primary_implementation() bean resolution.
172
+ if etype == "implements":
173
+ if from_fqn not in impl_of.get(to_fqn, []):
174
+ impl_of.setdefault(to_fqn, []).append(from_fqn)
175
+ if to_fqn not in ifaces_of.get(from_fqn, []):
176
+ ifaces_of.setdefault(from_fqn, []).append(to_fqn)
117
177
 
118
- return cls(_impl_of=impl_of, _ifaces_of=ifaces_of)
178
+ return cls(
179
+ _impl_of=impl_of,
180
+ _ifaces_of=ifaces_of,
181
+ _subtype_of=subtype_of,
182
+ _supertype_of=supertype_of,
183
+ )
119
184
 
120
185
 
121
186
  # ---------------------------------------------------------------------------