sourcecode 2.6.10__tar.gz → 3.0.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-2.6.10 → sourcecode-3.0.0}/CHANGELOG.md +171 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/PKG-INFO +3 -1
- {sourcecode-2.6.10 → sourcecode-3.0.0}/README.md +2 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/pyproject.toml +1 -1
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/archetype.py +11 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/cache.py +44 -3
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/caller_metrics.py +19 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/cli.py +629 -85
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/context_cache.py +9 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/contract_pipeline.py +14 -3
- sourcecode-3.0.0/src/sourcecode/deployment_prefix.py +229 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/java.py +7 -1
- sourcecode-3.0.0/src/sourcecode/envelope.py +193 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/explain.py +32 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/format_contract.py +11 -5
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/git_analyzer.py +74 -12
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/hibernate_strat.py +11 -4
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/migrate_check.py +13 -0
- sourcecode-3.0.0/src/sourcecode/posture.py +458 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/pr_impact.py +135 -16
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/prepare_context.py +126 -35
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/repository_ir.py +355 -14
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_endpoint.py +32 -8
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_graph.py +9 -1
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_intf.py +32 -6
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_txsec.py +114 -6
- sourcecode-3.0.0/src/sourcecode/schemas/envelope-v1.schema.json +74 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/security_posture.py +41 -8
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/semantic_integration_engine.py +11 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/serializer.py +52 -6
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_findings.py +44 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_impact.py +44 -10
- sourcecode-3.0.0/src/sourcecode/spring_profiles.py +218 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_security_audit.py +5 -3
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/validation_inference.py +58 -6
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/validation_surface.py +91 -0
- sourcecode-3.0.0/src/sourcecode/verify_repo.py +252 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/verify_rules.py +135 -12
- {sourcecode-2.6.10 → sourcecode-3.0.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/.gitignore +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/.ruff.toml +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/CONTRIBUTING.md +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/LICENSE +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/SECURITY.md +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/raw +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/scripts/perf_harness.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/compare.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/license.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/perf.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/functions/README.md +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-2.6.10 → sourcecode-3.0.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,5 +1,176 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.0.0] — 2026-07-28
|
|
4
|
+
|
|
5
|
+
**One answer per question, a contract around every answer, and a gate that can be
|
|
6
|
+
switched on.** Driven by the strategic re-triage of the 2.7.0 field audit: ten reported
|
|
7
|
+
defects collapsed into four root-cause kernels — scope & identity, evidence admission,
|
|
8
|
+
presentation contract, conditional resolution — and the flagship enforcement feature was
|
|
9
|
+
built on top of the kernels rather than beside them.
|
|
10
|
+
|
|
11
|
+
### Breaking
|
|
12
|
+
|
|
13
|
+
- **`pr-impact` defaults to JSON.** It was the only machine-consumable command defaulting
|
|
14
|
+
to text, while being the one command a pipeline gates on (`--fail-on`, exit codes).
|
|
15
|
+
`--format text` restores the previous output.
|
|
16
|
+
- **`endpoints --by-controller` keys are controller FQNs, not simple class names.** The
|
|
17
|
+
function documented FQN grouping and grouped by simple name, so two controllers sharing
|
|
18
|
+
a name in different packages became one entry: keycloak reported 120 groups for 123
|
|
19
|
+
controller classes, and three of them listed another package's routes as their own.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Executable contracts.** A repository declares its invariants in `.ask/contracts.yml`
|
|
24
|
+
— forbidden edges, endpoint-security requirements, and forbidden finding classes from
|
|
25
|
+
the transaction/security analyzers that already ship — and `ask verify` gates on them.
|
|
26
|
+
Baseline-relative by default (`--capture-baseline`, `--fail-on new|any|never`): a
|
|
27
|
+
codebase adopting contracts already violates them, and a gate that fails on all of it
|
|
28
|
+
is switched off the same afternoon. Exit codes match `verify-edit` (0 pass, 1 blocked,
|
|
29
|
+
2 unverified). Violation identity excludes source position, so moving code is not a new
|
|
30
|
+
violation. GitHub Actions workflow and generic CI recipes in
|
|
31
|
+
[docs/contracts.md](docs/contracts.md); the older `.ask/verify-rules.json` keeps working.
|
|
32
|
+
- **`ask posture --profile` / `--diff`** *(experimental)*. Profile *detection* shipped in 2.7.0 with
|
|
33
|
+
nothing consuming it. This resolves which conditional beans a profile set actually
|
|
34
|
+
wires — full `@Profile` semantics including `!`, `&`, `|` and parentheses — and reports
|
|
35
|
+
what each side of a `--diff` wires that the other does not, including the
|
|
36
|
+
security-configuration slice ("prod configures the request chain; dev activates no
|
|
37
|
+
security configuration"). A bean gated by a condition the analyzer does not evaluate is
|
|
38
|
+
reported as **unresolved**, never assumed active and never assumed absent. On a
|
|
39
|
+
repository that gates beans on properties most of the answer will be "unresolved" —
|
|
40
|
+
that is the honest shape of what ships, and why the command is marked experimental.
|
|
41
|
+
See [docs/posture.md](docs/posture.md).
|
|
42
|
+
- **A response envelope on every JSON payload.** `_meta` carries
|
|
43
|
+
`envelope_version`, `tool_version`, `command`, `scope` (path, repo root, and the prefix
|
|
44
|
+
every path in the payload is relative to), `run_id`, and the `inputs` the id is computed
|
|
45
|
+
over. `run_id` carries no timestamp, so two runs on an unchanged tree are byte-identical
|
|
46
|
+
and any change to the analyzer, the commit, the working tree or the repository
|
|
47
|
+
configuration changes it. MCP inherits it.
|
|
48
|
+
- **A published output contract.** `ask schema envelope-v1` prints the JSON Schema the
|
|
49
|
+
installed version emits, with the compatibility policy stated inside it. A conformance
|
|
50
|
+
battery validates real command output against it.
|
|
51
|
+
- **`--base` as an alias for `--since`**, and `-f` for `--format` on `review-pr` and
|
|
52
|
+
`verify-edit`. Additive: every existing spelling still works.
|
|
53
|
+
- **Endpoint admission classes.** The endpoint surface publishes `by_source` and
|
|
54
|
+
`semantic_model_endpoints`, so the totals from `endpoints`, `spring-audit` and
|
|
55
|
+
`retrieve endpoint-inventory` reconcile instead of contradicting each other.
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- **`--changed-only` reported `file_paths: []` on every run.** It filtered a key the
|
|
60
|
+
compact view never emits, so the one file-level surface of the changed-only envelope was
|
|
61
|
+
always empty — next to a non-empty `changed_files` proving otherwise. Both the cold and
|
|
62
|
+
the warm-cache paths had the same dead filter. The warm path also claimed
|
|
63
|
+
`cache_source: L2_view` for content that came from the L1 rebuild.
|
|
64
|
+
- **Three commands answered "how many endpoints?" with three numbers.** Broadleaf
|
|
65
|
+
225/220/220, openmrs 1/0/0, JobRunr 12/0/0. The difference is xml-mapped controllers and
|
|
66
|
+
router-DSL routes, which the semantic model does not index; `spring-audit` explained it
|
|
67
|
+
as "multi-prefix routes that collapse", which was measurably not the cause.
|
|
68
|
+
- **`impact` and `impact-chain` scored risk on incomparable scales.** `impact` bounds the
|
|
69
|
+
score to [0,100); `impact-chain` returned an unbounded total whose caller term was capped
|
|
70
|
+
at 20, flattening symbols whose caller counts differ by an order of magnitude (keycloak
|
|
71
|
+
printed 86.0 for two symbols and 1844.0 for a third). Both now use the same knee
|
|
72
|
+
compression, with the knee on the critical band edge — zero risk-level changes across a
|
|
73
|
+
16-symbol A/B — and publish `risk_score_raw` for ranking.
|
|
74
|
+
- **`review-pr` announced roles its own evidence gate had rejected.** A repository whose
|
|
75
|
+
only change was a string helper named `NameMapper.java` reported "1 MyBatis mapper(s) —
|
|
76
|
+
risk areas: persistence" while the file's own record said `artifact_type: source`. One
|
|
77
|
+
admission seam now serves the summary, the risk areas, the review-order ranking and the
|
|
78
|
+
per-file records. Aligning them exposed the gate rejecting true positives too:
|
|
79
|
+
persistence evidence knew JPA but not MyBatis/JDBC, and controller evidence knew Spring
|
|
80
|
+
MVC but not JAX-RS — keycloak's entire 676-endpoint surface.
|
|
81
|
+
|
|
82
|
+
## [2.7.0] — 2026-07-26
|
|
83
|
+
|
|
84
|
+
**The analyzer reads facts it had been walking past, and stops spending the context budget
|
|
85
|
+
it exists to save.** Driven by an external audit of 2.6.10 and validated by a field battery
|
|
86
|
+
across eleven real repositories plus an A/B against the previous release.
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- **Deployment prefix.** Neither `server.servlet.context-path` nor `spring.mvc.servlet.path`
|
|
91
|
+
was read anywhere, so an app deployed under `/app-server/api` was inventoried as `/v1/x` —
|
|
92
|
+
every URL wrong by the same constant, which is what makes the error invisible. Endpoints
|
|
93
|
+
now carry `effective_path` alongside the mapping-relative `path`, plus a
|
|
94
|
+
`deployment_prefix` block with per-source provenance. A value carrying a placeholder, or
|
|
95
|
+
declared only under a profile, is recorded but never imposed on every route.
|
|
96
|
+
- **Two unread profile signals.** Profile names came from one signal — the
|
|
97
|
+
`application-{profile}.yml` filename convention. Multi-document activation
|
|
98
|
+
(`spring.config.activate.on-profile`) and `@Profile` on beans are read now, and
|
|
99
|
+
`profile_conditional_beans` says WHICH beans each profile switches — routinely the
|
|
100
|
+
security filter chain.
|
|
101
|
+
- **A repo's own authorization gate on the endpoint surface.** Custom-gate detection fed
|
|
102
|
+
only the `spring-audit` posture block; every other surface reported `policy: none_detected`
|
|
103
|
+
for each endpoint of a repo whose authorization runs entirely through its own annotation.
|
|
104
|
+
Such endpoints now carry `policy: custom_gate_inferred` with the annotation as evidence,
|
|
105
|
+
and the model becomes `custom_annotation_based`. Coverage and specificity alone were
|
|
106
|
+
measured to be insufficient for a per-endpoint claim — they select caching and
|
|
107
|
+
documentation annotations — so the claim additionally requires an in-repo `@interface`
|
|
108
|
+
declaration. Structural, no name matching.
|
|
109
|
+
- **`explain --limit`** (default 50), capping the list sections with the truncation and the
|
|
110
|
+
exact total stated in `warnings`. `--limit 0` restores the full lists.
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
|
|
114
|
+
- **Cross-file `String` constants were not folded.** `@RequestMapping(Routes.BASE)` resolved
|
|
115
|
+
to nothing and "nothing" was emitted as the empty path, collapsing every handler of a
|
|
116
|
+
controller onto `GET /`. A repo-wide constant table is built from the pass the assembler
|
|
117
|
+
already runs; a name declared twice with different values is dropped, not guessed; what
|
|
118
|
+
still cannot be resolved is published as `path_resolution: "unresolved"` with the
|
|
119
|
+
expression, instead of a fabricated `/`. On keycloak this recovers three real endpoints
|
|
120
|
+
(`AuthZen.EVALUATION_PATH`, `AdapterConstants.K_LOGOUT`) with no route newly unresolved.
|
|
121
|
+
- **Types whose name sits on the line after the keyword** (`public class\n Name {`) were
|
|
122
|
+
not extracted.
|
|
123
|
+
- **Hibernate rewrite snippets quoted literal-blanked source**, emitting
|
|
124
|
+
`em.createNamedQuery("")` — dropping the query name, the one datum that makes the target
|
|
125
|
+
actionable.
|
|
126
|
+
- **Confidence described the lookup, not the answer.** `retrieve endpoint-security` graded
|
|
127
|
+
"high" whenever the reference resolved, so an endpoint with no policy and no finding came
|
|
128
|
+
back maximally confident about nothing. It is high only when evidence attaches, and an
|
|
129
|
+
explicit `evidence_absent` observation says which case it is.
|
|
130
|
+
- **Archetype counted signal diversity by cardinality**, which one dominant signal satisfies
|
|
131
|
+
trivially. "High" now also requires the top signal to supply at most 80% of the label's
|
|
132
|
+
score.
|
|
133
|
+
- **Cycle counts read as one command contradicting another** (`modernize` 15 tangles vs
|
|
134
|
+
`subsystem-coupling` 0 import cycles). Both are right and measure different graphs; a
|
|
135
|
+
shared reconciliation note now travels with both numbers.
|
|
136
|
+
- **`auth status` reported `pro: false`** while every Pro command ran under the
|
|
137
|
+
early-adoption unlock. It now reports the gating in force (`pro_gating`, `pro_effective`,
|
|
138
|
+
`pro_reason`).
|
|
139
|
+
- **`transaction-entrypoints` counted only `@Transactional` declared ON a controller**, so a
|
|
140
|
+
repo with 129 boundaries reported 1 entrypoint. Boundaries reachable from a controller
|
|
141
|
+
within 3 call hops are reported alongside, each labelled with its `entrypoint_basis`.
|
|
142
|
+
Rows that a signature-free FQN made indistinguishable (overloads) collapse with the count
|
|
143
|
+
kept as `occurrences`; rows that differ in any attribute stay separate.
|
|
144
|
+
- **`integration-inventory` said nothing four times**: identity keyed on
|
|
145
|
+
(kind, target-or-client) produced byte-identical rows. Rows collapse with `occurrences`,
|
|
146
|
+
and a null target carries the reason it is null. On Broadleaf: 9 rows → 4.
|
|
147
|
+
- **`cache warm <subdir>` warmed the whole monorepo**, populating a cache for a different
|
|
148
|
+
target than `ask <subdir>` reads. It warms exactly the path given and says so when that
|
|
149
|
+
differs from the git root.
|
|
150
|
+
- **`migrate-check --compact` shipped an empty `headline_blocker`**, forcing the reader back
|
|
151
|
+
into the full report. It names the weakest applicable axis, or says "none" /
|
|
152
|
+
"none_applicable". The guard against asserting a framework blocker without version
|
|
153
|
+
evidence is preserved.
|
|
154
|
+
- **`impact-chain` enumerations were unbounded.** Lists are capped; every total stays exact
|
|
155
|
+
in `metadata` and `truncated_lists`.
|
|
156
|
+
- **The profile signal was gated on the env-var scan**: a repo that declares profiles but
|
|
157
|
+
reads no environment variable published nothing about them — the exact shape the profile
|
|
158
|
+
signals were added for.
|
|
159
|
+
|
|
160
|
+
### Changed
|
|
161
|
+
|
|
162
|
+
- **`export --c4` omits the code level (C4 level 4) by default.** It enumerates every symbol
|
|
163
|
+
per directory and dominated the export: keycloak 18.6 MB → 2.5 MB, Broadleaf 9.7 MB →
|
|
164
|
+
1.1 MB. The omission is explicit in the payload (`included: false` with the reason and the
|
|
165
|
+
directory count) and `--c4-code` restores it.
|
|
166
|
+
|
|
167
|
+
### Notes
|
|
168
|
+
|
|
169
|
+
- Validated before release: full suite (3,869 passed), eleven repositories × eight commands
|
|
170
|
+
with no crash and valid JSON throughout, output identical across `PYTHONHASHSEED` values
|
|
171
|
+
on cold caches, and an A/B against 2.6.10 in which every difference maps to a change listed
|
|
172
|
+
above.
|
|
173
|
+
|
|
3
174
|
## [2.6.10] — 2026-07-25
|
|
4
175
|
|
|
5
176
|
**Identical runs now produce identical output.** Found by a field battery across twelve
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.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
|
|
@@ -232,6 +232,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
232
232
|
| Doc | What it covers |
|
|
233
233
|
|-----|----------------|
|
|
234
234
|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
|
|
235
|
+
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml`, enforce them in the edit loop and in CI |
|
|
236
|
+
| [posture.md](docs/posture.md) | What a profile set actually wires, and what could not be decided (experimental) |
|
|
235
237
|
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
|
|
236
238
|
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
|
|
237
239
|
| [PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md) | Free vs Pro, pricing model |
|
|
@@ -194,6 +194,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
194
194
|
| Doc | What it covers |
|
|
195
195
|
|-----|----------------|
|
|
196
196
|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
|
|
197
|
+
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml`, enforce them in the edit loop and in CI |
|
|
198
|
+
| [posture.md](docs/posture.md) | What a profile set actually wires, and what could not be decided (experimental) |
|
|
197
199
|
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
|
|
198
200
|
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
|
|
199
201
|
| [PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md) | Free vs Pro, pricing model |
|
|
@@ -604,12 +604,23 @@ class ArchetypeClassifier:
|
|
|
604
604
|
# Gini alone labeling a REST API an "engine") — is a single point of view and
|
|
605
605
|
# must not read as high confidence (field-eval Fase 0).
|
|
606
606
|
distinct_signals = len({e.signal for e in top.evidence if e.contribution > 0})
|
|
607
|
+
# Diversity by COUNT is satisfiable while one signal carries the
|
|
608
|
+
# verdict: an audited repo was labelled "engine" at high confidence on
|
|
609
|
+
# 1.500 of a 1.504 score — a fan-in Gini alone, with the second signal
|
|
610
|
+
# contributing 0.3%. Counting it as two views is a fiction, so a label
|
|
611
|
+
# whose top signal supplies almost all of its score cannot be "high"
|
|
612
|
+
# however many other signals nominally touch it.
|
|
613
|
+
_contributions = sorted(
|
|
614
|
+
(e.contribution for e in top.evidence if e.contribution > 0), reverse=True
|
|
615
|
+
)
|
|
616
|
+
top_signal_share = (_contributions[0] / top.score) if _contributions else 1.0
|
|
607
617
|
if (
|
|
608
618
|
confident_enough
|
|
609
619
|
and rel_margin >= 0.4
|
|
610
620
|
and mass_backed
|
|
611
621
|
and graph_backed
|
|
612
622
|
and distinct_signals >= 2
|
|
623
|
+
and top_signal_share <= 0.8
|
|
613
624
|
):
|
|
614
625
|
confidence = "high"
|
|
615
626
|
elif confident_enough and rel_margin >= 0.25 and mass_backed:
|
|
@@ -75,11 +75,52 @@ SCHEMA_VERSION: str = "2"
|
|
|
75
75
|
#: Bump to invalidate all L1 core caches (independent of snapshot version).
|
|
76
76
|
CORE_SCHEMA_VERSION: str = "1"
|
|
77
77
|
|
|
78
|
-
#:
|
|
79
|
-
#:
|
|
80
|
-
#:
|
|
78
|
+
#: Manual override for invalidating all L1 core caches. Rarely needed now that the
|
|
79
|
+
#: key carries :func:`analyzer_fingerprint`; kept as an escape hatch for cases the
|
|
80
|
+
#: fingerprint cannot see (a changed dependency, a corrected cache format).
|
|
81
|
+
#: Package version bumps must NOT bump this value.
|
|
81
82
|
ANALYZER_CACHE_VERSION: str = "1"
|
|
82
83
|
|
|
84
|
+
|
|
85
|
+
def analyzer_fingerprint() -> str:
|
|
86
|
+
"""Content hash of the analysis code, memoised for the process.
|
|
87
|
+
|
|
88
|
+
A cache key built only from the repository state and a hand-maintained version
|
|
89
|
+
constant cannot notice that the analyzer itself changed. That discipline failed
|
|
90
|
+
exactly as designed-by-humans disciplines do: five consecutive fixes to analysis
|
|
91
|
+
logic shipped without anyone bumping ``ANALYZER_CACHE_VERSION``, so an upgraded
|
|
92
|
+
install kept serving pre-fix results from cache on an unchanged commit — the
|
|
93
|
+
fixes looked inert until the user cleared the cache by hand.
|
|
94
|
+
|
|
95
|
+
Hashing file *content* (not mtime) keeps the key stable across reinstalls and
|
|
96
|
+
identical checkouts on different machines, so caches stay shareable. Any edit to
|
|
97
|
+
any module invalidates every entry: over-invalidation costs a re-analysis,
|
|
98
|
+
under-invalidation reports facts the current code would not produce.
|
|
99
|
+
|
|
100
|
+
Falls back to the package version when the source is unreadable (zipimport,
|
|
101
|
+
frozen builds) — degraded, never wrong-by-silence.
|
|
102
|
+
"""
|
|
103
|
+
global _ANALYZER_FINGERPRINT
|
|
104
|
+
if _ANALYZER_FINGERPRINT is not None:
|
|
105
|
+
return _ANALYZER_FINGERPRINT
|
|
106
|
+
digest = hashlib.sha256()
|
|
107
|
+
try:
|
|
108
|
+
pkg_root = Path(__file__).resolve().parent
|
|
109
|
+
sources = sorted(pkg_root.rglob("*.py"))
|
|
110
|
+
if not sources:
|
|
111
|
+
raise OSError("no analyzer sources found")
|
|
112
|
+
for src in sources:
|
|
113
|
+
digest.update(src.relative_to(pkg_root).as_posix().encode("utf-8"))
|
|
114
|
+
digest.update(src.read_bytes())
|
|
115
|
+
_ANALYZER_FINGERPRINT = digest.hexdigest()[:12]
|
|
116
|
+
except Exception:
|
|
117
|
+
from sourcecode import __version__ as _pkg_version
|
|
118
|
+
_ANALYZER_FINGERPRINT = f"pkg-{_pkg_version}"
|
|
119
|
+
return _ANALYZER_FINGERPRINT
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
_ANALYZER_FINGERPRINT: Optional[str] = None
|
|
123
|
+
|
|
83
124
|
#: Fields eligible for CAS deduplication (applied to top-level JSON dict keys).
|
|
84
125
|
_CAS_FIELDS: frozenset[str] = frozenset([
|
|
85
126
|
"file_paths",
|
|
@@ -40,3 +40,22 @@ CALLER_METRIC_RECONCILIATION: str = (
|
|
|
40
40
|
"references or DI-interface resolution). The top-level impact.direct_callers array "
|
|
41
41
|
"may be truncated for output size — use stats.direct_caller_count for the true total."
|
|
42
42
|
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Cycle / tangle metrics come from TWO different graphs. Both are correct; they
|
|
46
|
+
# answer different questions, and without saying so the pair reads as one command
|
|
47
|
+
# contradicting another (external audit 2026-07-25: modernize reported 15 cyclic
|
|
48
|
+
# tangles while retrieve subsystem-coupling reported import_cycles: 0).
|
|
49
|
+
CYCLE_METRIC_RECONCILIATION: str = (
|
|
50
|
+
"Cycle metrics differ across commands BY DESIGN. modernize.cross_module_tangles "
|
|
51
|
+
"is computed over the SYMBOL dependency graph, aggregated to subsystem packages: "
|
|
52
|
+
"coupling_type=cyclic means two subsystems reference each other (a 2-cycle "
|
|
53
|
+
"between package groups). The module-graph metrics (import_cycles, cyclic_density, "
|
|
54
|
+
"scc_mass — used by archetype and the subsystem-coupling retrieval intent) are "
|
|
55
|
+
"computed over the MODULE/DIRECTORY graph, are bounded for cost (node/edge caps), "
|
|
56
|
+
"and count strongly-connected components among modules. A repo can therefore "
|
|
57
|
+
"show mutual package-level coupling (tangles > 0) with no module-level SCC "
|
|
58
|
+
"(import_cycles = 0): the coupling exists between package groups inside the same "
|
|
59
|
+
"module. Neither number invalidates the other — read tangles for decomposition "
|
|
60
|
+
"risk and import_cycles for module-graph topology."
|
|
61
|
+
)
|