sourcecode 3.6.0__tar.gz → 3.8.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-3.6.0 → sourcecode-3.8.0}/CHANGELOG.md +452 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/PKG-INFO +32 -3
- {sourcecode-3.6.0 → sourcecode-3.8.0}/README.md +31 -2
- {sourcecode-3.6.0 → sourcecode-3.8.0}/pyproject.toml +1 -1
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/archetype.py +43 -16
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/cache_model.py +10 -7
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/change_plan.py +5 -1
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/cli.py +665 -197
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/compare.py +5 -3
- sourcecode-3.8.0/src/sourcecode/contract_init.py +419 -0
- sourcecode-3.8.0/src/sourcecode/defect_identity.py +142 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/degradation.py +52 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/java.py +15 -31
- sourcecode-3.8.0/src/sourcecode/environment_resolution.py +361 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/explain.py +11 -0
- sourcecode-3.8.0/src/sourcecode/git_checkout.py +149 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/migrate_check.py +52 -2
- sourcecode-3.8.0/src/sourcecode/non_coverage.py +198 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/output_budget.py +7 -2
- sourcecode-3.8.0/src/sourcecode/pipe_contract.py +208 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/posture.py +144 -2
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/pr_comment_renderer.py +13 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/prepare_context.py +110 -3
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/repository_ir.py +61 -4
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/result.py +24 -9
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps.py +3 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_endpoint.py +5 -5
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_graph.py +5 -5
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_impact.py +19 -7
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_intf.py +4 -4
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_struct.py +5 -5
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_txsec.py +5 -5
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/serializer.py +132 -66
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_findings.py +139 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_impact.py +18 -1
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_profiles.py +193 -1
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_tx_analyzer.py +10 -0
- sourcecode-3.8.0/src/sourcecode/target_admission.py +168 -0
- sourcecode-3.8.0/src/sourcecode/test_gap_ranking.py +363 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/token_estimate.py +36 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/verify_edit.py +32 -9
- {sourcecode-3.6.0 → sourcecode-3.8.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/.gitignore +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/.ruff.toml +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/CONTRIBUTING.md +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/LICENSE +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/SECURITY.md +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/raw +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/scripts/perf_harness.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/cache.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/envelope.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/license.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/perf.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/functions/README.md +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-3.6.0 → sourcecode-3.8.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,5 +1,457 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [3.8.0] — 2026-08-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **The security surface publishes what it does not answer** (CL-2, CL-7, and the framing half
|
|
10
|
+
of CL-5). A report that lists what it found and says nothing about what it never looks at
|
|
11
|
+
invites silence to be read as absence — and the audit that raised this found a credential
|
|
12
|
+
versioned in three deployment descriptors *by hand*, because nothing here reads outside Java
|
|
13
|
+
and Spring configuration.
|
|
14
|
+
- One authority, `sourcecode/non_coverage.py`, read by three surfaces: the `non_coverage`
|
|
15
|
+
block in the `spring-audit` payload, the command's own `--help`, and the README section —
|
|
16
|
+
all rendered from the same table, because a curated list beside a generated one is how
|
|
17
|
+
`endpoints` went missing from every help list.
|
|
18
|
+
- Four rows for the security surface: no dataflow or taint (NC-001), no secrets outside Java
|
|
19
|
+
and Spring configuration (NC-002), filter-chain order not reconstructed (NC-003), no CVE
|
|
20
|
+
matching (NC-004). Each states why it is out of scope rather than unimplemented, and what
|
|
21
|
+
does answer it. Two more state the migration boundary (NC-005, OpenRewrite takes the
|
|
22
|
+
recipes this publishes) and the environment boundary (NC-006, answered as far as a
|
|
23
|
+
repository can by `posture --resolve-environments`).
|
|
24
|
+
- The evaluator's argument for publishing it is commercial, not ethical: *"un producto que
|
|
25
|
+
publica sus límites no se compara por amplitud; se compara por profundidad, que es donde
|
|
26
|
+
gana."*
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **Two claims corrected with measured figures.** `--compact` is documented as the smallest
|
|
31
|
+
answer, **not the cheapest run** — 13.3 s cold on BroadleafCommerce against `spring-audit`
|
|
32
|
+
3.6 s and `posture` 1.9 s, 0.3 s warm — with the reason to warm before a session stated where
|
|
33
|
+
the claim is made (CL-3). And the product is positioned as the **diagnosis layer** until an
|
|
34
|
+
executor ships, in the field's own numbers (7/10 as a report generator, 5.5/10 as a
|
|
35
|
+
development tool) rather than argued with (CL-5).
|
|
36
|
+
|
|
37
|
+
- **`ask trend` is a top-level command, and capture is automatable** (P-4). The *series* is the
|
|
38
|
+
asset — a repository that captured a baseline at each release has a history nobody can
|
|
39
|
+
reconstruct afterwards, and one that did not never will — so reading it is no longer two words
|
|
40
|
+
deep, and [`docs/baseline-ci.yml`](docs/baseline-ci.yml) captures one per tag and publishes the
|
|
41
|
+
trend as a build artifact. `ask baseline trend` is the same command.
|
|
42
|
+
- The read-only half was a **documentation** gap and is closed where the auditor meets it:
|
|
43
|
+
`--dir` already existed, and the default now says *why* it is inside the repository (the
|
|
44
|
+
history travels with the code, not with a vendor) and that an audit which must leave the tree
|
|
45
|
+
untouched writes elsewhere. README and the user guide say the same.
|
|
46
|
+
- ⚠Adding the command surfaced the **C4-1 shape a sixth time**: `ask trend` was registered,
|
|
47
|
+
working and documented, and the CLI answered *"'trend' does not exist"* — because the
|
|
48
|
+
dispatcher matched against a **hand-written set of subcommand names**. It is derived from the
|
|
49
|
+
registry now, and the battery asserts every registered command is dispatchable.
|
|
50
|
+
|
|
51
|
+
- **`ask posture --resolve-environments` — which profile set actually runs, and the worst one
|
|
52
|
+
that could** (CL-8 / M9.5). `posture --diff` was called the strongest thing this product does
|
|
53
|
+
and it stopped at the repository boundary: which profile set runs is decided by the
|
|
54
|
+
deployment, so the answer was conditional and a field evaluator closed the last hops by hand
|
|
55
|
+
with `grep` (build profile → the property the build filters → a placeholder present in no
|
|
56
|
+
config file → no `context-param` in any descriptor → therefore nothing decides it).
|
|
57
|
+
- Those hops are now mechanical. Every artefact that can set `spring.profiles.active` is read
|
|
58
|
+
— config files, Maven/Gradle properties, `web.xml` context parameters, `Dockerfile` `ENV`
|
|
59
|
+
and `-D` arguments, Compose and Kubernetes manifests, launch scripts — each publishing what
|
|
60
|
+
it says with `file:line`. The verdict is `decided_in_repository`, `artefacts_disagree` (two
|
|
61
|
+
deployments, never a contradiction to resolve by picking one), or **`NOT DECIDED IN THIS
|
|
62
|
+
REPOSITORY`**.
|
|
63
|
+
- Every admissible profile set is then resolved over one parse and ranked by what it leaves
|
|
64
|
+
open, so the payload names the worst case and, where the repository does decide, how far the
|
|
65
|
+
shipped set is from it: *"one environment variable away from dev"*.
|
|
66
|
+
- **`open_by_rule` and `access_not_decided` are counted separately.** A readable rule that
|
|
67
|
+
permits a request unauthenticated is not the same fact as no readable rule matching it, and
|
|
68
|
+
folding them together would publish the confident security falsehood this command exists to
|
|
69
|
+
prevent. The reading says which is which.
|
|
70
|
+
- A value found in the repository is published as a default, never a guarantee:
|
|
71
|
+
`SPRING_PROFILES_ACTIVE` in the process environment outranks every artefact, and this
|
|
72
|
+
analysis cannot see the process environment.
|
|
73
|
+
|
|
74
|
+
- **`ask verify --init` derives the contracts a repository already satisfies** (C3-30). The gate
|
|
75
|
+
had no way to acquire what it gates on: nobody hand-writes contracts for a 3 300-file
|
|
76
|
+
monolith, so the honest gate (zero contracts is `unverified`, closed as C3-15) stayed empty —
|
|
77
|
+
and the gate is the recurring half of the value story, where an audit is bought once.
|
|
78
|
+
- Three shapes, each written with the measurement behind it: a path prefix whose endpoints all
|
|
79
|
+
carry the same policy today (`require_endpoint_security`), an audit pattern that fires
|
|
80
|
+
nowhere (`forbid_finding`), and an injection edge between two annotated populations that
|
|
81
|
+
does not occur, both populations large enough that the absence is a pattern rather than an
|
|
82
|
+
accident (`forbidden_edge`).
|
|
83
|
+
- **Every rule is executed before it is written.** The derived set runs through the same engine
|
|
84
|
+
`verify` runs, and anything that fails on the tree it came from is dropped and reported —
|
|
85
|
+
`verify --init` followed by `verify` passes by construction, asserted as a round trip in the
|
|
86
|
+
battery, together with the proof that the populated gate goes red when the invariant breaks.
|
|
87
|
+
- Violations that exist today are deliberately not proposed: that is debt for
|
|
88
|
+
`--capture-baseline`, a different claim from an invariant, and the payload says so per
|
|
89
|
+
rejected candidate.
|
|
90
|
+
- `--dry-run` prints without writing; an existing contracts file is never replaced without
|
|
91
|
+
`--force`.
|
|
92
|
+
|
|
93
|
+
- **`delta` and `contract-diff` take git refs** (C3-33). Both compared two *checkouts* while
|
|
94
|
+
`review-pr` in the same CLI already took `--since`, so comparing two commits meant
|
|
95
|
+
orchestrating worktrees first. In the evaluation that recorded this, that cost coverage rather
|
|
96
|
+
than convenience: the evaluator ran the full catalogue against a client monolith under a
|
|
97
|
+
promise to leave the environment byte-identical and **omitted both commands** rather than
|
|
98
|
+
create worktrees in someone else's repository.
|
|
99
|
+
- `ask delta --base-ref origin/main --head-ref HEAD [--repo <path>]`, same for
|
|
100
|
+
`contract-diff`. Two checkouts positionally still work, and the payload publishes a
|
|
101
|
+
`comparison` block saying which basis it used — with both refs and their resolved commits.
|
|
102
|
+
- **Reading a ref writes nothing to the repository.** `git archive` streams the tree into a
|
|
103
|
+
temporary directory that is removed on the way out: no `git worktree add` (which registers
|
|
104
|
+
administrative state under `.git/worktrees` and leaves it behind if the process dies), no
|
|
105
|
+
checkout, no stash, no index read. The battery asserts `git status` and `git worktree list`
|
|
106
|
+
are identical before and after.
|
|
107
|
+
- A ref this repository does not have is refused by name (`git_ref_not_found`, exit 1) and
|
|
108
|
+
never substituted with something nearby.
|
|
109
|
+
|
|
110
|
+
### Fixed
|
|
111
|
+
|
|
112
|
+
- **`retrieve` stopped publishing scores nothing computed** (C3-19, **`entities[].score` and
|
|
113
|
+
`explanation.score` are nullable**). `retrieve blast-radius` returned eighty dependents each
|
|
114
|
+
carrying `"score": 0.0`, beside an explanation whose own score was 92.43 — and the step that
|
|
115
|
+
orders those entities says in its own docstring that no score is computed. The same default put
|
|
116
|
+
a zero on every entity of every intent, and an `explanation` block with `winner: null,
|
|
117
|
+
score: 0.0` on the intents that return what they found rather than choose a winner: the shape
|
|
118
|
+
the field called *a ranking block that never ran*.
|
|
119
|
+
- Both fields are `None` when nothing wrote them. The order is real and structural, so the
|
|
120
|
+
payload states it: `entities_ranked_by` — *"reach from the target (direct before indirect),
|
|
121
|
+
then identity — a structural order, not a per-entity score"*.
|
|
122
|
+
- `retrieve` remains `[PARKED]`; this is the honesty fix the tier does not excuse.
|
|
123
|
+
|
|
124
|
+
- **`archetype` no longer scores an unmeasured HTTP surface as an absent one** (C3-7). The
|
|
125
|
+
command declares `endpoints` as a missing signal on runs with no root to read — and then
|
|
126
|
+
scored as if the answer were **0**, which is a measured statement. Inside the scorer that zero
|
|
127
|
+
did two things at once: it refuted `api-first` and it fired `worker`'s `event_no_http`
|
|
128
|
+
evidence, so a repository nobody measured came back classified as an event worker with the
|
|
129
|
+
reason published as if it were a finding (I-3/R9, inside a score).
|
|
130
|
+
- The count is nullable now. Unmeasured contributes nothing and says so in its own evidence
|
|
131
|
+
row; `event_no_http` requires the absence of HTTP as a *measured* fact. A measured zero
|
|
132
|
+
behaves exactly as before, which the battery asserts alongside the unmeasured case.
|
|
133
|
+
- Measured while closing it, and recorded rather than acted on: `archetype` on
|
|
134
|
+
BroadleafCommerce takes **9.3 s** (the field reported 22 s) and returns two high-confidence
|
|
135
|
+
dimensions of four, so the tier stays `[EXPERIMENTAL]` — the cost complaint does not
|
|
136
|
+
reproduce at that magnitude, and a command with two high-confidence answers is not a
|
|
137
|
+
candidate for `parked`.
|
|
138
|
+
|
|
139
|
+
- **The summary stopped costing more than the analyses it summarises** (C3-6, C3-21). Measured on
|
|
140
|
+
BroadleafCommerce with nothing warm: `--compact` **19.3 s → 13.3 s**, and with the parse cache
|
|
141
|
+
warm **14.0 s → 7.9 s**; `endpoints` **3.3 s → 1.4 s**. Two duplications inside one process, both
|
|
142
|
+
removed:
|
|
143
|
+
- The **core view was built twice on every cold run** — once for the L1 cache write and once for
|
|
144
|
+
the RIS update — and building it rebuilds the CIR. One repository state has one core view; both
|
|
145
|
+
writers now read it.
|
|
146
|
+
- The **endpoint extractor parsed every file itself** while `build_repo_ir` read the
|
|
147
|
+
content-addressed parse cache for the same bytes. A run that does both paid for the same parse
|
|
148
|
+
twice, and a warm cache measurably bought `endpoints` nothing — a fact this product published
|
|
149
|
+
in its own cache model. Same key, same extractor, same capture signature: the entry either side
|
|
150
|
+
writes is the entry the other reads. The cache-model rows for `endpoints` and the root command
|
|
151
|
+
are re-measured accordingly.
|
|
152
|
+
- The inversion is **narrowed, not gone**: `--compact` is still slower than `spring-audit`
|
|
153
|
+
(3.6 s) or `posture` (1.9 s), because it builds the summary *and* the core view where those
|
|
154
|
+
build one analysis each.
|
|
155
|
+
- **C3-21 does not reproduce on 3.7.0**: the cache hit that cost 2 647 ms now costs 1.6 s for
|
|
156
|
+
`explain` against a 1.6 s cold run, and the snapshot hit for `--compact` is 0.29 s. Recorded as
|
|
157
|
+
measured, not assumed closed.
|
|
158
|
+
- The battery pins the two mechanisms rather than wall-clock figures: a second extraction must
|
|
159
|
+
re-parse nothing, the cached and uncached answers must be identical, and one root run must
|
|
160
|
+
build the core view once.
|
|
161
|
+
|
|
162
|
+
- **A comment can no longer take a whole file out of the graph** (E-1). The declaration joiner
|
|
163
|
+
decided whether a line *starts* a type declaration by scanning raw text, so a comment carrying
|
|
164
|
+
`class` or `interface` followed by an identifier looked like a declaration head with its brace
|
|
165
|
+
on a later line — `/** Implements the interface only for the legacy path. */`, or a trailing
|
|
166
|
+
`// starter class is not an utility class` on an annotation. The join then swallowed the
|
|
167
|
+
annotation and the real declaration into one entry beginning with `@`, which the parser reads
|
|
168
|
+
as a pending annotation and never examines: the file contributed **zero symbols** — no type,
|
|
169
|
+
no endpoint, no transaction boundary — and a file that contributes nothing looks exactly like
|
|
170
|
+
a file with nothing in it, which is why no field report could ever name this.
|
|
171
|
+
- Comments are stripped before the keyword scan (block state carried across lines, string
|
|
172
|
+
literal aware), and the brace that ends a join must also be code, so a commented `{` no
|
|
173
|
+
longer cuts a real multi-line declaration in half.
|
|
174
|
+
- Measured A/B over six repositories: **open-banking-gateway recovers 6 types, three of them
|
|
175
|
+
Spring Boot application classes**; petclinic, eureka, openmrs-core, BroadleafCommerce and
|
|
176
|
+
keycloak are unchanged, and **no repository loses a symbol**.
|
|
177
|
+
|
|
178
|
+
- **`generate-tests` ranks by what depends on the file, not by how the file is named**
|
|
179
|
+
(C3-13, **`untested_sources[]` entries change shape**). Two rules, both name matching, both
|
|
180
|
+
measured on openmrs-core: admission kept only files whose name ends in one of five suffixes
|
|
181
|
+
(`Service.java`, `Controller.java`, `Repository.java`, `Mapper.java`, `RestController.java`),
|
|
182
|
+
reducing **866 production files to 11 candidates**; and coverage was a filename pair, so
|
|
183
|
+
`PersonServiceImpl` was a gap for want of a `PersonServiceImplTest`. What remained was ordered
|
|
184
|
+
by how often the substring `"public "` appears in the first 16 KB — while `blast_radius`,
|
|
185
|
+
transaction boundaries and endpoint exposure were already computed elsewhere in the same
|
|
186
|
+
product and never consulted.
|
|
187
|
+
- **Coverage is now a reach fact**: a type is covered when a test source reaches it — named
|
|
188
|
+
directly, or reached along the call, instantiation and injection edges a blast radius
|
|
189
|
+
already walks, through the interface the container wires it behind, or as a supertype of
|
|
190
|
+
something a test exercises. One forward traversal from every test type: 0.01 s on
|
|
191
|
+
BroadleafCommerce. Reaching is not asserting, so the coverage figure is a floor and the gap
|
|
192
|
+
list is a ceiling, and `notes` says so.
|
|
193
|
+
- **Admission is the population**, not a naming convention: openmrs-core 866 production files
|
|
194
|
+
→ **161 untested**, BroadleafCommerce 2 765 → **1 494**, published as `population` beside
|
|
195
|
+
the list.
|
|
196
|
+
- **Order is the measured axes** — endpoints reached, transaction boundaries declared, classes
|
|
197
|
+
that depend on it — reusing `caller_reach`, `spring_impact._collect_endpoints` and
|
|
198
|
+
`spring_semantic.boundaries_declared_within` rather than deriving them again. The weights
|
|
199
|
+
that fold the three into `score` are published with `rank_weights_basis: "assumption, not a
|
|
200
|
+
measurement"`, and the order is reproducible from the axes without accepting them.
|
|
201
|
+
- `untested_sources[]`/`test_gaps[]` rows drop `rank_score`, `public_method_count` and
|
|
202
|
+
`has_framework_annotations` — measurements of the replaced basis — and carry
|
|
203
|
+
`endpoints_reached`, `transaction_boundaries` and `caller_classes` instead. `path`, `score`
|
|
204
|
+
and `reason` are unchanged. The new `test_gap_ranking` block publishes the basis, the
|
|
205
|
+
population and the caps.
|
|
206
|
+
- Cost, measured cold: BroadleafCommerce 11.1 s → **15.3 s**, openmrs-core 5.1 s → 10.2 s. A
|
|
207
|
+
run whose IR cannot be built keeps the filename algorithm and publishes the
|
|
208
|
+
`test_reach_graph` signal with what taking it costs the answer (I-8).
|
|
209
|
+
|
|
210
|
+
- **`generate-tests` publishes its time budget, and a cache no longer defeats it** (C3-1). The
|
|
211
|
+
30 s cap was reachable only through `SOURCECODE_TESTS_TIMEOUT_MS`, a name in no help text —
|
|
212
|
+
the one knob that turns an empty answer into an answer was invisible to whoever was holding
|
|
213
|
+
the empty answer. `--timeout <seconds>` is now a documented flag (the variable still works;
|
|
214
|
+
the flag wins), and an exhausted budget publishes `analysis_budget` carrying the new
|
|
215
|
+
`time_budget` cap: *"an empty list here means the walk stopped, NOT that the repository has
|
|
216
|
+
nothing"*, with the budget, its source, and how to raise it.
|
|
217
|
+
- Closing it surfaced a sharper defect, measured: **the cache key ignored the budget**, so a
|
|
218
|
+
run that exhausted 2 s answered the re-run at 30 s from cache — the remedy the payload
|
|
219
|
+
names did nothing at all. The budget is now part of the cache identity, and an exhausted
|
|
220
|
+
result is never stored: an unfinished walk is worth re-running.
|
|
221
|
+
- Measured while closing it: the full scan on openmrs-core (3 300 files, cold cache) takes
|
|
222
|
+
**3.35 s** and returns 13 untested sources, so the field's empty payload does not reproduce
|
|
223
|
+
and the default budget is not the constraint it was taken for. The ranking half of C3-13
|
|
224
|
+
stays open — the command still matches file names while `blast_radius`, transactional
|
|
225
|
+
writes and endpoint exposure are already computed.
|
|
226
|
+
|
|
227
|
+
- **`review-pr` no longer counts documentation as a runtime change** (C3-11b). The field
|
|
228
|
+
reported a diff of 227 `.md` files as `runtime_changes: 228` — while every one of those
|
|
229
|
+
entries carried `artifact_type: "documentation"` and `change_effect: "documentation file (no
|
|
230
|
+
runtime impact)"`. The list contradicted its own members. Reproduced on a real git repository
|
|
231
|
+
(12 `.md` files + one touched controller): **13 → 1**. The classifier was never wrong;
|
|
232
|
+
membership was "not noise and not a build manifest", which admits everything else, and the
|
|
233
|
+
admission seam (K2) now asks whether the admitted type can carry runtime behaviour at all.
|
|
234
|
+
- Nothing is dropped: the twelve are reported under `non_runtime_changes` with the same
|
|
235
|
+
evidence and effect statement, and the GitHub comment names them by count so it cannot look
|
|
236
|
+
like it missed part of the diff.
|
|
237
|
+
- The split is asserted **against the effect statements themselves** — a type whose published
|
|
238
|
+
statement disclaims impact must be in the non-runtime set — so it cannot drift from the
|
|
239
|
+
prose it is derived from (C4-1).
|
|
240
|
+
|
|
241
|
+
- **One profile population, whatever surface is asked** (C1-18, **`spring_profiles` changes on
|
|
242
|
+
repositories with resource bundles or resource folders**). Reproduced on a fixture first: the
|
|
243
|
+
same repository in one session answered `["qa","dev"]` in the default view, `["dev","prod",
|
|
244
|
+
"staging"]` in `posture` and `["dev","prod","qa","staging"]` under `--agent`. Three
|
|
245
|
+
populations under one name — and every conditional-security finding is keyed on that set, so
|
|
246
|
+
the default agent surface was answering the profile question with the population that had
|
|
247
|
+
lost the environments.
|
|
248
|
+
- Authority `spring_profiles.profile_population`: four named signals — the
|
|
249
|
+
`application-{profile}` filename, the per-environment overlay directory,
|
|
250
|
+
`spring.config.activate.on-profile` / `spring.profiles` inside config documents, and
|
|
251
|
+
`@Profile` on a bean — unioned once, with `by_signal` published so each name's provenance
|
|
252
|
+
is auditable. The Java stack detector, `posture` and the serializer's profile section all
|
|
253
|
+
read it, asserted per surface.
|
|
254
|
+
- Closing it exposed two false positives in the signals it inherited, both fixed
|
|
255
|
+
structurally rather than by name (VAI): an `application-{x}` file counts only **beside its
|
|
256
|
+
base config** — alfresco-community-repo's `alfresco/messages/application-model_de.properties`
|
|
257
|
+
and 19 siblings were reported as twenty environments, now none — and an overlay directory
|
|
258
|
+
counts only when it **holds a config file** — spring-petclinic's `db/`, `messages/`,
|
|
259
|
+
`static/` and `templates/` were reported as four environments, now `mysql, postgres`, its
|
|
260
|
+
real profiles.
|
|
261
|
+
|
|
262
|
+
- **The token-saving ratio is published, and published as a ceiling** (CL-1). `token_economy`
|
|
263
|
+
emitted `emitted`, `baseline_raw_read` and `saved` — three numbers a reader divides into a
|
|
264
|
+
multiple and then quotes. The multiple travelled without the label the block put on the
|
|
265
|
+
inputs, which is how "up to 55×" ends up in a room. `ratio_upper_bound` is now emitted with
|
|
266
|
+
a `ratio_basis` that states the counterfactual making it a ceiling — every cited file and
|
|
267
|
+
build manifest read **in full and once** — the band we measured for the ceiling itself
|
|
268
|
+
(**3.8×–37.6×** over `--compact` and `--agent` on spring-petclinic, BroadleafCommerce,
|
|
269
|
+
openmrs-core and keycloak; nothing near 55×), and the field's 10×–20× read of the saving an
|
|
270
|
+
agent actually realizes.
|
|
271
|
+
- `realized_saving` is `null` with its reason rather than a number: which files an agent would
|
|
272
|
+
truly have read is not observable from this process, and a `0` there would read as "no
|
|
273
|
+
saving" (I-3).
|
|
274
|
+
|
|
275
|
+
- **`spring-audit` counts defects as well as observations** (C2-5). A rule fires per
|
|
276
|
+
observation; a reader counts repairs. The audit published only the first number and let it
|
|
277
|
+
stand for the second: on openmrs-core `ConceptServiceImpl#checkIfLocked` carried **six
|
|
278
|
+
TX-006 findings, one per call site, for one annotated method with one fix**, and the
|
|
279
|
+
ledger's original witness is a private `@Transactional` method that draws TX-001 *and*
|
|
280
|
+
TX-006 for the same repair. Measured on the fleet: **openmrs-core 38 findings → 29
|
|
281
|
+
defects, BroadleafCommerce 19 → 14**.
|
|
282
|
+
- A defect is `(category, defect_kind, symbol)` — the thing you edit, and what is wrong
|
|
283
|
+
with it. `defect_kind` is **declared by the rule itself** (TX-001 and TX-006 both
|
|
284
|
+
declare `proxy_bypass`) and defaults to the rule's own id, so a rule that declares
|
|
285
|
+
nothing is never merged into another by omission, and there is no rule table maintained
|
|
286
|
+
beside the rules to drift out of date (C4-1).
|
|
287
|
+
- Nothing is filtered. `findings[]` keeps every observation and each one now names its
|
|
288
|
+
`defect_id`; the new `defects[]` rows carry `rule_ids`, `witness_count` and the witness
|
|
289
|
+
ids, so the grouping is auditable in both directions. `summary` publishes
|
|
290
|
+
`total_findings`, `total_defects`, `defects_by_severity` and a `counts_note` stating
|
|
291
|
+
which is which — `by_severity` and `by_category` keep counting observations, because a
|
|
292
|
+
count that changes basis under an unchanged name is the same defect wearing a new suit.
|
|
293
|
+
- A defect takes the **strongest** severity and confidence among its witnesses, and its id
|
|
294
|
+
is keyed on the identity, not the witnesses — acquiring a second witness next run does
|
|
295
|
+
not rename it, so a baseline keeps matching it.
|
|
296
|
+
|
|
297
|
+
- **`migrate-check` lists the blockers; hygiene is counted, not listed** (C2-6, **default
|
|
298
|
+
payload changes**). On openmrs-core the default report carried 310 findings of which **184
|
|
299
|
+
were `java_8_best_practice` advisory hygiene** — findings that block no version and that
|
|
300
|
+
every readiness score already excludes. A reader scanning the array met three advisory
|
|
301
|
+
entries for every two blockers. The emitted list now carries the blockers, ordered
|
|
302
|
+
most-severe first (**310 → 126 listed, 912 KB → 717 KB**), and `--include-hygiene` restores
|
|
303
|
+
the entries.
|
|
304
|
+
- **The floor cuts the list, never a figure.** `summary.by_severity`, `by_rule`,
|
|
305
|
+
`by_migration_target`, `total_findings`, `hygiene_findings`, `blocking_count` and every
|
|
306
|
+
dimension score are byte-identical to the unfloored run and still cover the whole
|
|
307
|
+
population — verified as an equality, not a claim.
|
|
308
|
+
- It is published as a cap, not applied in silence: `findings_floor` (the `severity_floor`
|
|
309
|
+
row of `CAP_EFFECTS`, I-8) states what was removed, what stayed exact, and the flag that
|
|
310
|
+
restores it, so `len(findings)` is never read as the total.
|
|
311
|
+
- The other half of the ledger row — "headline score reads 0/100 while real blockers are
|
|
312
|
+
481" — was already closed and re-measured here: hygiene is out of the aggregate, and
|
|
313
|
+
openmrs's 0 is `min(jakarta 0, hibernate 0)` with `jdk_modernization` (58) excluded by
|
|
314
|
+
design. The score was honest; the finding list was the noise.
|
|
315
|
+
|
|
316
|
+
## [3.7.0] — 2026-08-01
|
|
317
|
+
|
|
318
|
+
**The exit-code contract and the C3 surface block.** Seven rows closed: the two the field named
|
|
319
|
+
as blocking for CI (exit codes over correct answers), the fourth and fifth appearance of a
|
|
320
|
+
curated list beside real data, and three surfaces that published a promise the payload did not
|
|
321
|
+
keep.
|
|
322
|
+
|
|
323
|
+
Minor and not patch, because a pipeline can see the difference: `plan` exits 1 where it exited 0
|
|
324
|
+
over a target it never resolved (C3-29), `ask <cmd> | head` exits 0 where a correct run used to
|
|
325
|
+
exit non-zero (C3-28), `--output FILE` carries the whole answer where it was silently trimmed
|
|
326
|
+
(C3-17), `--agent` publishes sections it used to omit (C3-10), and a path-shaped target that was
|
|
327
|
+
refused as ambiguous now resolves (C3-35).
|
|
328
|
+
|
|
329
|
+
### Fixed
|
|
330
|
+
|
|
331
|
+
- **A broken output pipe is no longer a failed run** (C3-28, **exit code changes for
|
|
332
|
+
`ask <cmd> | head`**). `ask repo-ir . --force | head -c 100` returned the correct bytes and
|
|
333
|
+
exit 1; under `set -e` that stops a pipeline with no error anywhere to explain it — the field
|
|
334
|
+
named it one of two blockers for CI. One authority now says what a closed stream means
|
|
335
|
+
(`pipe_contract.py`, installed at the entry point): **a broken output stream changes nothing
|
|
336
|
+
except where the remaining bytes go.** The descriptor is redirected to the null device on the
|
|
337
|
+
first broken write and the command finishes and exits on its own terms.
|
|
338
|
+
- **It does not overwrite the command's own verdict.** `ask impact <ambiguous target> | head`
|
|
339
|
+
still exits 1, because a consumer that stopped reading has no opinion about whether the
|
|
340
|
+
analysis resolved its target.
|
|
341
|
+
- Redirecting before the shutdown flush is what keeps Python from printing
|
|
342
|
+
`Exception ignored in: <_io.TextIOWrapper …>` and exiting 120 — the same defect wearing a
|
|
343
|
+
different number.
|
|
344
|
+
- **The wrapper covers `.buffer`, which is the whole fix**: payloads are written as bytes
|
|
345
|
+
through `sys.stdout.buffer` at the single emit seam, so a text-only wrapper sits beside the
|
|
346
|
+
one write this exists for. Measured: with the text wrapper alone, nothing changed.
|
|
347
|
+
- Only visible above a pipe buffer, which is why it looked intermittent: `endpoints` on a
|
|
348
|
+
small repository exits 0 either way, `repo-ir` on the same repository did not.
|
|
349
|
+
|
|
350
|
+
- **An unresolved target has one exit code across every command** (C3-29, **`plan` now exits 1
|
|
351
|
+
where it exited 0**). `plan <unknown> <repo>` ran to completion, emitted a plan-shaped payload
|
|
352
|
+
of zeros with `resolution: "not_found"` and exited **0**, while `impact` on the same input
|
|
353
|
+
exited 1 — so a gate could not tell "nothing to review" from "I never found what you asked
|
|
354
|
+
about". One authority (`target_admission.py`), four commands rebound (`impact`,
|
|
355
|
+
`impact-chain`, `plan`, `explain`), and the two other copies of the same literal set
|
|
356
|
+
(`compare`, `change_plan`) now read it instead of restating it.
|
|
357
|
+
- **Ambiguity is the same fact, and it was not in the field report.** A target matching
|
|
358
|
+
several classes returns `ambiguous_path`, empty results and a message asking for the full
|
|
359
|
+
FQN — the command declined to answer — and `impact` exited **0** on it. Measured on a
|
|
360
|
+
purpose-built two-class fixture, since no battery repository carries the shape.
|
|
361
|
+
- Unresolved is **1, not 2**: 2 is reserved by the `verify` family for a run that could not
|
|
362
|
+
look, and this run looked. Partial and expanded resolutions stay 0 — they are answers about
|
|
363
|
+
the target the caller named.
|
|
364
|
+
- `plan`'s `Note:` on stderr is gone with it: the payload already carries the statement, and
|
|
365
|
+
a successful-looking run should not be narrating on stderr (the `plan` half of C3-34).
|
|
366
|
+
|
|
367
|
+
- **`--help` reaches inside command groups** (C4-7). `ask cache model` — what a warm buys each
|
|
368
|
+
command, per layer, including the commands it buys nothing for — appeared in no help text at
|
|
369
|
+
all: the root catalogue was generated (C4-1/C4-2) but the Cache and Auth blocks under it were
|
|
370
|
+
three lines somebody typed by hand. The blocks are now built from the registered groups, so a
|
|
371
|
+
subcommand is listed the moment it is registered; a group too large to name in full (`retrieve`,
|
|
372
|
+
29 parked intents) publishes its **exact count** and a pointer, never silence. The battery
|
|
373
|
+
fails if a subcommand of a listed group is missing, or if a collapsed group's count drifts.
|
|
374
|
+
|
|
375
|
+
- **A successful run says nothing on stderr — measured over the commands, not over a list**
|
|
376
|
+
(C3-34, the `repo-ir` half). `ask repo-ir . --force` wrote an 82-byte size advisory on a run
|
|
377
|
+
that exited 0 with the IR on stdout, which PowerShell 5.1 raises as a `NativeCommandError`.
|
|
378
|
+
The advisory is terminal-gated now, like every other notice, and so is the `--exclude`
|
|
379
|
+
directory warning and the output-budget trim warning found beside it.
|
|
380
|
+
- **The list was the defect.** `tests/test_stderr_purity_matrix.py` enumerated 13 commands by
|
|
381
|
+
hand for the fourth time in three releases; the rows are now **discovered from the CLI**,
|
|
382
|
+
with every command either driven or carrying a written reason it cannot be. Nine more
|
|
383
|
+
commands are driven as a result, `cache` subcommands included.
|
|
384
|
+
- The `repo-ir` row builds a repository large enough for the advisory to actually fire and
|
|
385
|
+
**asserts it fired**, because a row that never reaches the branch proves nothing.
|
|
386
|
+
|
|
387
|
+
- **`--output FILE` is no longer trimmed to an agent's context window** (C3-17). The payload
|
|
388
|
+
budget exists because a context window is finite — it is a constraint on **stdout**. Written
|
|
389
|
+
to a file it cut the answer anyway, dropped `key_dependencies` entirely, and the note
|
|
390
|
+
explaining the cut advised `--output`, the flag already in use. Two of six call sites had the
|
|
391
|
+
rule and four did not (`prepare-context`, `modernize`, the cached-view rebuild, and `impact`
|
|
392
|
+
in part), so it now lives in one seam (`cli._apply_budget`) and a battery fails if a seventh
|
|
393
|
+
call site decides for itself.
|
|
394
|
+
- **The cache had the same defect one layer down**, found while field-checking the seam:
|
|
395
|
+
`prepare-context` stored the document *after* trimming, so the first stdout run poisoned the
|
|
396
|
+
cache and every later `--output FILE` hit received a stdout-sized answer. The cache stores
|
|
397
|
+
the analysis now and the budget is applied per run — measured on alfresco-community-repo:
|
|
398
|
+
stdout 5 files, cache hit to a file 26.
|
|
399
|
+
- **`--full` says what it does.** It raises the caps (boundaries and DTO mappers in full,
|
|
400
|
+
`file_relevance` to 40); it never removed them — under `--agent --full` the file list stayed
|
|
401
|
+
capped at 40 of 710 while the flag's help promised "remove truncation limits".
|
|
402
|
+
|
|
403
|
+
- **`--agent` cannot publish less than `--compact`** (C3-10). `--compact` documents
|
|
404
|
+
`security_surface` "when custom security annotations detected" and closes with "use `--agent`
|
|
405
|
+
for maximum signal", while `--agent` was assembled from its own hand-written list of sections:
|
|
406
|
+
measured on BroadleafCommerce it omitted `deployment` and `language_version` outright, and
|
|
407
|
+
nothing stopped the security surface going the same way. Both views now read one authority
|
|
408
|
+
(`serializer.JAVA_SPRING_SECTIONS`), and the battery fails on any section `--compact` publishes
|
|
409
|
+
that `--agent` does not.
|
|
410
|
+
|
|
411
|
+
- **A path that names one file resolves to that file** (C3-35). Every resolver reduced a
|
|
412
|
+
path-shaped target to its basename before anything looked at it, so
|
|
413
|
+
`ask impact src/main/java/com/a/Service.java` answered `ambiguous_path` and offered
|
|
414
|
+
`com.a.Service` **and** `com.b.Service` — being more specific made the answer worse. A path is
|
|
415
|
+
matched against the `source_file` each symbol came from, strongest tier first (exact, then
|
|
416
|
+
module-relative, then parent-relative), and nested types collapse to the type the file is about
|
|
417
|
+
(on eureka, `DiscoveryClient.java` declares its outer class and five inner ones). One authority
|
|
418
|
+
in `target_admission`, because three graphs answer target questions — the repo IR, and the CIR
|
|
419
|
+
that `explain` and `impact-chain` read, both of which used to answer `not_found` for a path.
|
|
420
|
+
Parity checked on eureka: by path and by name give byte-identical `stats`.
|
|
421
|
+
|
|
422
|
+
- **`verify-edit` stops paying for a diff it has already proved empty** (C3-32). It computed the
|
|
423
|
+
change set and then built the HEAD CIR *and* the working CIR unconditionally — on a clean tree
|
|
424
|
+
the second is the first by construction. Measured on a clean ofbiz-framework: **5.9 s -> 1.7 s**
|
|
425
|
+
warm. The shortcut is taken only when git actually answered: a failed `git diff` also returns an
|
|
426
|
+
empty list, and reading that as "nothing changed" would trade dead cost for a false green.
|
|
427
|
+
|
|
428
|
+
- **`spring-audit --compact`** (C3-31). The one analysis command with no summary mode: 1.99 MB for
|
|
429
|
+
14 findings in the field, *"a context overflow against an LLM with no filter in between"*. The
|
|
430
|
+
weight is not the findings — on BroadleafCommerce `security_posture.endpoints` is 113 KB of a
|
|
431
|
+
178 KB report, and the counts it supports are published beside it. `--compact` caps that list and
|
|
432
|
+
`findings` to their top 5, ordered by what asks something of the reader (`probably_exposed`
|
|
433
|
+
first; most severe first), and recomputes nothing: **178 KB -> 25 KB with every count
|
|
434
|
+
identical**. A flag changes how much is emitted, never the shape (C2-10) — each list stays a list
|
|
435
|
+
and the totals live in a `*_cap` sibling that exists only when the cap bit.
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
### Documentation
|
|
439
|
+
|
|
440
|
+
- **Field evaluation #6 of 3.5.0 recorded** (`.planning/FIELD-EVAL-6-2026-08-01.md`, defect
|
|
441
|
+
ledger, development roadmap). Full 27-command catalogue, repository left byte-identical,
|
|
442
|
+
scored 8/10. Every reported defect was re-measured on 3.6.0 before it was written down: two
|
|
443
|
+
do not reproduce (one closed here as C3-15, one by the 3.5.0 admission authority) and the
|
|
444
|
+
re-measurement found two the evaluation did not report.
|
|
445
|
+
- **New rows**: C1-18 (profile population differs per command, and the narrower one is what an
|
|
446
|
+
agent reads) · C3-28/C3-29 (**exit codes that lie over correct answers** — a broken pipe
|
|
447
|
+
exits non-zero on a successful run, `plan` exits 0 on a target it did not resolve while
|
|
448
|
+
`impact` exits 1) · C3-30 (`verify --init`) · C3-31…C3-34 · C4-7 (`cache model` in no help
|
|
449
|
+
panel) · P-4 (`baseline` history nobody automated) · CL-7 (non-coverage: no dataflow, no
|
|
450
|
+
secrets outside Java/YAML, filter order not reconstructed) · CL-8 (`posture --diff` answers
|
|
451
|
+
conditionally because the profile is decided outside the repository).
|
|
452
|
+
- **The executive roadmap gains what the product does *not* do**, published beside the
|
|
453
|
+
capabilities, and the evaluation table is current through eval #6.
|
|
454
|
+
|
|
3
455
|
## [3.6.0] — 2026-08-01
|
|
4
456
|
|
|
5
457
|
**The P0 block and the C1/C2 backlog.** Nine rows closed, three closed by measurement alone
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.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
|
|
@@ -251,7 +251,7 @@ from it.
|
|
|
251
251
|
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
252
252
|
| `plan` / `compare` / `delta` / `contract-diff` | supported | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
|
|
253
253
|
| `validation` | supported | request-body validation coverage and gaps | |
|
|
254
|
-
| `baseline capture\|diff
|
|
254
|
+
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend <dir>` reads the series | trend reporting, not gating. Baselines land in `.ask/baselines` **inside the repository** — the history travels with the code, not with a vendor; an audit that must not write passes `--dir`. Automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
|
|
255
255
|
| `retrieve` | parked | typed knowledge queries over the model | |
|
|
256
256
|
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
257
257
|
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
@@ -275,6 +275,34 @@ Honest limits worth knowing before you rely on it:
|
|
|
275
275
|
- Architecture classification is tuned for Spring MVC layered apps; SPI/plugin models (e.g. Quarkus extensions) may be misclassified. JAX-RS subresource-locator endpoint recall is ~65%.
|
|
276
276
|
- Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.
|
|
277
277
|
|
|
278
|
+
### What the security surface does not answer
|
|
279
|
+
|
|
280
|
+
Published because a product that states its limits is not compared on breadth — it is
|
|
281
|
+
compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
|
|
282
|
+
reading JSON sees the same boundary a buyer reads here.
|
|
283
|
+
|
|
284
|
+
| Not covered | Why | What answers it |
|
|
285
|
+
|---|---|---|
|
|
286
|
+
| **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
|
|
287
|
+
| **Secrets outside Java and Spring configuration — a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
|
|
288
|
+
| **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
|
|
289
|
+
| **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
|
|
290
|
+
|
|
291
|
+
Two more boundaries worth stating in the same voice:
|
|
292
|
+
|
|
293
|
+
| Not covered | Why | What answers it |
|
|
294
|
+
|---|---|---|
|
|
295
|
+
| **Applying a migration — nothing here edits source.** | This is the diagnosis layer: it measures what must change and what each change would reach. Rewriting code is an execution problem with an established executor, and duplicating it would mean maintaining a second, worse one. | OpenRewrite. `migrate-check` publishes the recipe each finding carries (`recipes[]`), which is the input that executor takes. |
|
|
296
|
+
| **What the process environment sets at start-up — the profile set, properties and secrets a container is given.** | Nothing in a repository can observe the environment of a process that has not started. A value read from a file here is the default the repository ships, never a guarantee of what runs. | `ask posture --resolve-environments` reads every artefact in the repository that names the profile set, says when none of them decides it, and ranks the admissible sets by what each leaves open. |
|
|
297
|
+
|
|
298
|
+
**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
|
|
299
|
+
must change, what each change reaches, and what a gate should block — and it removes none of
|
|
300
|
+
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
|
|
301
|
+
and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
|
|
302
|
+
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
303
|
+
input.
|
|
304
|
+
|
|
305
|
+
|
|
278
306
|
---
|
|
279
307
|
|
|
280
308
|
## Pricing
|
|
@@ -348,7 +376,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
348
376
|
| Doc | What it covers |
|
|
349
377
|
|-----|----------------|
|
|
350
378
|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
|
|
351
|
-
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml
|
|
379
|
+
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI |
|
|
380
|
+
| [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
|
|
352
381
|
| [posture.md](docs/posture.md) | What a profile set actually wires — down to which endpoints its filter chain permits — and what could not be decided (experimental) |
|
|
353
382
|
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
|
|
354
383
|
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
|
|
@@ -213,7 +213,7 @@ from it.
|
|
|
213
213
|
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
214
214
|
| `plan` / `compare` / `delta` / `contract-diff` | supported | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
|
|
215
215
|
| `validation` | supported | request-body validation coverage and gaps | |
|
|
216
|
-
| `baseline capture\|diff
|
|
216
|
+
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend <dir>` reads the series | trend reporting, not gating. Baselines land in `.ask/baselines` **inside the repository** — the history travels with the code, not with a vendor; an audit that must not write passes `--dir`. Automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
|
|
217
217
|
| `retrieve` | parked | typed knowledge queries over the model | |
|
|
218
218
|
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
219
219
|
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
@@ -237,6 +237,34 @@ Honest limits worth knowing before you rely on it:
|
|
|
237
237
|
- Architecture classification is tuned for Spring MVC layered apps; SPI/plugin models (e.g. Quarkus extensions) may be misclassified. JAX-RS subresource-locator endpoint recall is ~65%.
|
|
238
238
|
- Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.
|
|
239
239
|
|
|
240
|
+
### What the security surface does not answer
|
|
241
|
+
|
|
242
|
+
Published because a product that states its limits is not compared on breadth — it is
|
|
243
|
+
compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
|
|
244
|
+
reading JSON sees the same boundary a buyer reads here.
|
|
245
|
+
|
|
246
|
+
| Not covered | Why | What answers it |
|
|
247
|
+
|---|---|---|
|
|
248
|
+
| **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
|
|
249
|
+
| **Secrets outside Java and Spring configuration — a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
|
|
250
|
+
| **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
|
|
251
|
+
| **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
|
|
252
|
+
|
|
253
|
+
Two more boundaries worth stating in the same voice:
|
|
254
|
+
|
|
255
|
+
| Not covered | Why | What answers it |
|
|
256
|
+
|---|---|---|
|
|
257
|
+
| **Applying a migration — nothing here edits source.** | This is the diagnosis layer: it measures what must change and what each change would reach. Rewriting code is an execution problem with an established executor, and duplicating it would mean maintaining a second, worse one. | OpenRewrite. `migrate-check` publishes the recipe each finding carries (`recipes[]`), which is the input that executor takes. |
|
|
258
|
+
| **What the process environment sets at start-up — the profile set, properties and secrets a container is given.** | Nothing in a repository can observe the environment of a process that has not started. A value read from a file here is the default the repository ships, never a guarantee of what runs. | `ask posture --resolve-environments` reads every artefact in the repository that names the profile set, says when none of them decides it, and ranks the admissible sets by what each leaves open. |
|
|
259
|
+
|
|
260
|
+
**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
|
|
261
|
+
must change, what each change reaches, and what a gate should block — and it removes none of
|
|
262
|
+
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
|
|
263
|
+
and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
|
|
264
|
+
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
265
|
+
input.
|
|
266
|
+
|
|
267
|
+
|
|
240
268
|
---
|
|
241
269
|
|
|
242
270
|
## Pricing
|
|
@@ -310,7 +338,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
310
338
|
| Doc | What it covers |
|
|
311
339
|
|-----|----------------|
|
|
312
340
|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
|
|
313
|
-
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml
|
|
341
|
+
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI |
|
|
342
|
+
| [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
|
|
314
343
|
| [posture.md](docs/posture.md) | What a profile set actually wires — down to which endpoints its filter chain permits — and what could not be decided (experimental) |
|
|
315
344
|
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
|
|
316
345
|
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
|