Metadata-Version: 2.4
Name: sourcecode
Version: 4.11.0
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
License-File: LICENSE
Keywords: agents,ai,codebase,context,developer-tools,llm
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Requires-Dist: defusedxml>=0.7
Requires-Dist: mcp<2,>=1.2
Requires-Dist: pathspec>=1.0
Requires-Dist: ruamel-yaml>=0.18
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.24
Provides-Extra: ast
Requires-Dist: tree-sitter-javascript>=0.21; extra == 'ast'
Requires-Dist: tree-sitter-typescript>=0.21; extra == 'ast'
Requires-Dist: tree-sitter>=0.21; extra == 'ast'
Provides-Extra: dev
Requires-Dist: mcp<2,>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.15; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.2; extra == 'mcp'
Description-Content-Type: text/markdown

# ASK Engine

> **ASK — Actionable Software Knowledge.** Persistent structural intelligence for AI coding agents.

**Context · Impact · Migration · Architecture · Review — everything from one structural model.**

![Version](https://img.shields.io/badge/version-4.11.0-blue)
![Python](https://img.shields.io/badge/python-3.9%2B-green)

> **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
> command still works as a deprecated alias (it prints a one-line notice and forwards to
> `ask`) and remains the Python/PyPI package name for now. The authoritative version is
> whatever `ask version` reports. See [docs/PRODUCT_IDENTITY.md](docs/PRODUCT_IDENTITY.md).

---

## The problem

Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. On small and mid-sized repos that cost is seconds; on large Java/Spring monoliths, repo-wide semantic composition can be minutes. Multiply that by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.

ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, later invocations reuse pre-built context whenever their command can consume the warmed layers. The repo doesn't change? The cache doesn't expire.

**The cache is not a performance optimization. It is what makes ASK Engine usable as infrastructure rather than a one-off tool.**

---

## Proof — measured on real repos

| Repo | Size | Cold scan | Cache hit | Speedup |
|------|------|-----------|-----------|---------|
| Keycloak | 7,885 Java files | 10.5s | 0.6s | **~17x** |
| BroadleafCommerce | 2,985 Java files | 2.7s | 0.3s | **~9x** |

These numbers are cache-layer benchmarks, not a promise for every command. Per-symbol queries and compact context benefit most. Inventory commands scale with file count. Repo-wide/deep compositions such as `risk`, `audit-report` and large `spring-audit` runs can take minutes on multi-thousand-endpoint repositories and belong in a supervised or nightly job unless CI sets an explicit budget.

With the right command class, ASK Engine becomes **constant infrastructure** inside agent loops — call the fast/context surfaces before edits and reserve deep compositions for the points where their evidence is worth the runtime.

**Large-repo controls.** Pass `--progress stderr` (or `--progress file:run.log`)
for line heartbeats in a non-TTY supervised run — with the file being read so
far and an ETA for the stage being measured. `ASK_PROGRESS` sets the same thing
in the environment. Long repo-wide/deep runs also write durable records under
`~/.sourcecode/runs/<repo-hash>/` by default, not inside the audited repository;
set `ASK_RUNS_IN_REPO=1` only when repo-local `.ask/runs` records are intentional.
Set `ASK_MAX_ANALYSIS_SECONDS=<seconds>` to fail before starting a repo-wide/deep
command whose configured budget is below its safe floor. Use
`ask audit-report --from-risk risk.json` to package an existing risk run instead
of recomputing it.

**What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
IR) and the **compact view**. Pass `--agent` to warm the agent view as well. Deeper projections
are separate keys and are *not* covered by either — `--full`, `--env-map` and a raised `--depth`
recompute on first use, as do most `prepare-context` tasks. Measured on a 3,342-file Spring
monolith: `cache warm` 103s → `--compact --git-context` 1s (hit), but `--agent --full --env-map
--depth 20` still 171s (miss).

**One rule for invalidation, and a table that names every command.** Every layer keys on the
exact tree state: any change to the analysed files invalidates it, committed or not. Which of
*your* commands a warm helps — the answer, only the shared work, or nothing — is published per
command: `ask cache model`, or [docs/CACHE.md](docs/CACHE.md).

---

## Install

```bash
# Homebrew (macOS / Linux)
brew tap haroundominique/sourcecode && brew install sourcecode

# pip / pipx
pipx install sourcecode        # or: pip install sourcecode

ask version                    # ask 4.11.0 — and, on a build that has aged,
                               # how many releases have probably shipped since
```

> **Package vs. command.** The install package is named `sourcecode` this release
> (renaming the distribution is a separate, breaking change). Installing it gives you the
> canonical **`ask`** command plus the deprecated **`sourcecode`** alias.

> **Platforms.** Developed and tested on macOS and Linux; every release runs its full
> battery there. **Windows/PowerShell is a target we cannot verify:** the CLI is written
> for it — UTF-8 streams are forced at both console entry points, a successful run writes
> nothing to stderr (PowerShell 5.1 raises `NativeCommandError` on any stderr write), and
> the MCP server strips the BOM PowerShell puts on stdin — but no Windows runner exists in
> the battery. Three separate field reports of console mojibake (`—` rendering as `â€"`)
> have never reproduced under measurement, and the only variable those reports share is the
> platform we cannot exercise (C3-3, C3-12, C3-38 in the
> [defect ledger](docs/DEFECT-LEDGER.md)). On Windows, prefer `--output <file>` over shell
> redirection, and report a rendering problem rather than assuming it is known.

---

## Quickstart

**Start with these four.** In three independent field evaluations they carried most of the
measured value, and `posture --diff` is the one no evaluator found an equivalent for —
commercial or open source.

```bash
# What does each profile set ACTUALLY wire — and what changes between them?
# Resolves conditional beans and the filter chain, then diffs effective endpoint access.
ask posture /path/to/repo --diff dev:prod

# Every REST endpoint with its effective path (context-path + servlet path resolved),
# its inferred security policy and a confidence per endpoint.
ask endpoints /path/to/repo

# Spring semantic audit: transactional anomalies (private @Transactional = silent
# CGLIB no-op), security surface, request-body validation.
ask spring-audit /path/to/repo

# Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
ask migrate-check /path/to/repo --compact
# Add --target-jdk 25 to make the LTS route explicit.
```

**Then the three that finish the sentence the four above start.** A profile-set answer stays
conditional until you know which set the deployment starts with, a gate nobody can populate is
a gate nobody runs, and a defect ranked without its reach is a linter note:

```bash
# Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
# descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
# says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
# every admissible set by what it leaves reachable without authentication.
ask posture /path/to/repo --resolve-environments

# Derive the contracts this repository already satisfies, execute each one before
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
ask verify /path/to/repo --init

# Same derivation under a read-only constraint: prints what it would declare and
# writes nothing — the form an audit of somebody else's repository can run.
ask verify /path/to/repo --init --dry-run

# What each defect actually costs once reach, access, write effect and the shape of
# the input path are in it — ordered, every factor traceable to the command that owns it.
ask risk /path/to/repo
```

Then the everyday loop:

```bash
# High-signal structural summary — warm cache ~0.3s, cold 2–10s
ask --compact

# Blast radius: what breaks if this class changes?  (target the INTERFACE, not the Impl)
ask impact OrderService /path/to/repo

# Onboard to an unfamiliar codebase
ask onboard /path/to/repo

# PR review: risk, test gaps, changed modules
ask review-pr /path/to/repo --since main

# CI gate on NEW violations only, instead of on pre-existing debt
ask verify /path/to/repo --init               # derive the contracts, don't hand-write them
ask verify /path/to/repo --capture-baseline   # accept today's debt, once
ask verify /path/to/repo                      # then: only new violations block
```

> **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
> monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
> executes each before writing it — init followed by verify passes by construction.
> A repository that starts declaring contracts already violates them somewhere; `ask verify`
> is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
> reality instead of being switched off on day one.
> `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
> time, for trend reporting rather than blocking.

Full command reference: **[docs/USER_GUIDE.md](docs/USER_GUIDE.md)** · posture in depth:
**[docs/posture.md](docs/posture.md)**.

---

## Capabilities

Everything is computed from one cached structural model. Seven groups:

### 1 · Structural Context
Bounded, noise-free repo context designed to drop straight into an agent's context window.
`ask --compact` · `ask --agent` · `ask onboard` · `ask cold-start`
→ [reference](docs/USER_GUIDE.md#core-commands)

### 2 · Impact Analysis
Blast radius from a class or interface — reverse dependencies, through Spring DI, to the HTTP endpoints a change reaches.
`ask impact` · `ask impact-chain` (blast radius; `--with-findings` for TX/SEC audit findings) · `ask pr-impact`
→ [reference](docs/USER_GUIDE.md#core-commands)

### 3 · Architecture Intelligence
The system map: module graph, dependency views, REST surface, per-class summaries, and a symbol-level IR for downstream tooling.
`ask export` · `ask repo-ir` · `ask endpoints` · `ask explain`
→ [reference](docs/USER_GUIDE.md#core-commands)

### 4 · Migration & Modernization
Is this codebase ready to upgrade? Per-dimension readiness (Jakarta / Spring Boot / JDK / Hibernate), located blockers, an effort estimate, and — with `--blast-radius` — the endpoints whose call path runs through each blocker, so the re-test plan is ordered by regression scope.
`ask migrate-check` · `ask modernize`
→ [migrate-check reference](docs/migrate-check.md) · [MODERNIZATION.md](docs/MODERNIZATION.md)

### 5 · Spring Analysis
Deterministic Spring semantics: transactional anomalies (e.g. `@Transactional` on a private method = silent CGLIB no-op), security surface, request-body validation.
`ask spring-audit` · `ask validation`
→ [reference](docs/USER_GUIDE.md#core-commands)

### 5b · Runtime Posture *(experimental — and the most differentiated thing here)*
What a profile set **actually wires**: which conditional beans register, which do not, and which conditions could not be decided at all — then the effective endpoint access that follows from the filter chain. `--diff` answers the question nobody else answers in one command: *what changes between `dev` and `prod`, across every endpoint at once.*
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
→ [posture.md](docs/posture.md)

**`--diff-ref` makes it a gate instead of a report.** `--diff` moves the profile set; `--diff-ref origin/main:HEAD` (or `--since origin/main`, which compares a ref with the working tree) moves the *tree* under one profile set and answers *did this branch open an endpoint*. `--fail-on opened` exits 1 when it did. Both refs are read with `git archive` — nothing is written to the repository. The comparison is keyed on the request (`METHOD path`), counts requests only one side serves, and never reports a rule that disappeared as protection gained.
`ask posture . --since origin/main --fail-on opened`

**`--resolve-environments` carries it past the edge of the repository.** Every answer above
is conditional on a profile set, and which set runs is decided by the deployment. This flag
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
`web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
`decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
parse and publishes the worst. A field audit closed those five hops by hand with grep before
the flag existed.
`ask posture . --resolve-environments`

Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
hole with the condition named, never folded into active or inactive. **A posture answer that
guesses is a confident security falsehood — the worst failure mode this tool has.**

### 5c · Composed Risk *(experimental)*
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
join over the endpoint and symbol ids these commands already share with each other:
`severity_effective = defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`. The
product of the published factors **is** the published score — decomposable to the six
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
The last two factors describe the input path: a query assembled by concatenation, a bounded
HTTP-input-to-query-sink path when ASK can prove one, and a route accepting a body with no
declared constraint. General taint remains `NC-001` and is published in the payload's own
`non_coverage` block.
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
→ [reference](docs/USER_GUIDE.md)

### 6 · Developer Workflows
The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
`ask review-pr` · `ask fix-bug` · `ask prepare-context`
→ [reference](docs/USER_GUIDE.md#typical-workflows)

### 7 · Utilities
`ask rename-class` (word-boundary Java rename) · `ask chunk-file` (split large files for agents) · `ask cache` (status / warm / model / clear / freshness)
→ [reference](docs/USER_GUIDE.md)

---

## Command tiers

A tier says **what an output is worth relying on** — it is a stability promise, not a value
ranking, and not the [pricing tier](docs/PRODUCT_TIERS.md) (Free/Pro gates repository size,
never capability). `posture` is the most differentiated command in the product *and* it is
experimental: both are true, and they are two different facts.

| Tier | Promise | Commands |
|---|---|---|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
| **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `archetype` |
| **parked** | kept working, no longer developed | `retrieve` |

The same table is printed by `ask --help`, and both are generated from one authority
(`cli.COMMAND_TIERS`) — the battery fails if a command is in no tier, or if this file drifts
from it.

---

## Every command, in one table

*`ask --help` shows a short header; this is the full surface. If you only read one row, read
`posture`.*

| Command | Tier | Answers | Note |
|---|---|---|---|
| `posture` | supported | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
| `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
| `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
| `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
| `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
| `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
| `spring-audit` | core | transactional anomalies + security configuration/exposure + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review |
| `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
| `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
| `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
| `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
| `verify-edit` | supported | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
| `--compact` / `--agent` | — | bounded structural context for an agent | flags of the root command, not commands: not tiered |
| `onboard` / `explain` / `cold-start` | supported | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
| `export` / `repo-ir` / `schema` | supported | tool-agnostic views (C4, module graph, integrations); symbol-level IR; published JSON Schemas | |
| `modernize` | supported | coupling hubs, cycles, dead zones, refactor candidates | |
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
| `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 |
| `validation` | supported | request-body validation coverage and gaps | |
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend .` reads the series (a repository path or a baselines directory), `ask baseline diff .` compares the tree against its newest point | 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`. `capture --auto` is the unattended form (one baseline per commit, never rewrites one, never fails the build) — automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
| `retrieve` | parked | typed knowledge queries over the model | |
| `archetype` | experimental | evidence-based architectural archetype | |
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
| `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `cache model [path]` explains what a warm buys per command; `activate` too |

---

## What it does — and doesn't

**ASK Engine reduces exploration cost.** It accelerates context acquisition and computes
blast radius; it does not replace reading code — it reduces how often an agent needs to.
All signals are **static and deterministic** (annotations, import graph, file structure) —
no runtime analysis, no LLM guessing.

Honest limits worth knowing before you rely on it:

- `impact` on an **implementation** class (`OrderServiceImpl`) returns 0 callers in Spring Boot — callers inject the interface. **Always target the interface.**
- `no_security_signal` on an endpoint means *no recognized method-level annotation*, **not** "unsecured" — Spring Security filter chains and custom authorization annotations show as `no_security_signal` unless taught via config (below).
- `spring-audit` / `impact-chain` are **Java/Spring only**; non-Java repos return `spring_detected: false`.
- Event topology (`--type events`) resolves Spring `ApplicationEvent` / `@EventListener` chains only — **not** Kafka/RabbitMQ/Redis routes.
- 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%.
- Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.

### What the security section is, and what it does not answer

**What it reads:** the security *configuration and exposure* of a repository — which
rules the request chain declares, which endpoints they leave open, which controls are
present but disabled, and which custom gates can be bypassed, each with the file and
line that says so.

**What it is not:** a vulnerability scanner. No value flows through a program here, so
an injection, a deserialization sink or a logic flaw inside a method body is not looked
for, and its absence from the report is not evidence (NC-001, below).

**Where it is strongest:** given a defect somebody else found — a scanner finding, a
line from a review — `ask impact <symbol>` and `ask risk` quantify what it reaches: the
endpoints, the transactional boundaries and the modules downstream of it, with the
confidence of each hop. That is the question a taint scanner does not answer.

Published because a product that states its limits is not compared on breadth — it is
compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
reading JSON sees the same boundary a buyer reads here.

| Not covered | Why | What answers it |
|---|---|---|
| **General request-input-to-sink taint analysis.** | `ask risk` includes a bounded slice for annotated HTTP parameters, positional calls in repository Java sources and known query sinks. Anything broader 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) for complete taint. What this product adds on top is reachability and, for the bounded slice, whether an annotated HTTP input reaches a known concatenated query sink. |
| **Secrets outside Java, Spring configuration and the deployment descriptors — a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
| **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. |
| **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. |

Two more boundaries worth stating in the same voice:

| Not covered | Why | What answers it |
|---|---|---|
| **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. |
| **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. |


And one about the endpoint surface itself:

| Not covered | Why | What answers it |
|---|---|---|
| **HTTP surface that is not a Spring handler mapping — a servlet declared in `web.xml` or registered as a `ServletRegistrationBean`, a container-level mapping, a static console mounted by a library.** | The endpoint population is projected from the Spring route model: one entry per handler mapping. A servlet is reachable over HTTP and is not in that model, so it is absent from `endpoints`, from the access verdicts derived from it, and from every ratio keyed on the total. Merging a second population into that count would move a published figure and every ratio with it, so the population is declared before it is widened. | Read the deployment descriptors for `<servlet-mapping>` entries and the Spring configuration for `ServletRegistrationBean` beans. Field evaluation #9 found a monitoring console mounted this way, behind a credential `ask spring-audit` did report (SEC-007) at a path nothing here listed. |

And one about labelled data:

| Not covered | Why | What answers it |
|---|---|---|
| **Whether a labelled member actually leaves the process on a given route — field-level dataflow through mappers, DTOs, serializers and projections.** | Exposure here is measured at TYPE granularity over the same call reach every other command walks: a route reaches the labelled type, or its signature names it. Whether the mapping in between keeps the labelled member is a dataflow question, and answering it by approximation would put a confident `no` on a route that does leak. So `call_reach` is published as a supremum and says so. | Read the mapping on the routes this answer ranks first — they are the ones worth a human — and label the DTO too if it carries the member, which makes the route `signature` instead of `call_reach`. |

And one about who calls a route:

| Not covered | Why | What answers it |
|---|---|---|
| **Whether a route is called from outside this repository — another service, a mobile app, a partner, a cron job, or a client whose URL is assembled at run time.** | The join reads the TypeScript/JavaScript checked in beside the server and only the call shapes whose verb and path are written at the call site. That is a floor on who calls a route and can never be a ceiling: the repository cannot observe consumers it does not contain. So a route with no call site here is published as a candidate for deletion, never as dead API. | Access logs or an API gateway answer who really calls a route. The opposite direction is decisive without them: a client call matching no route is a request this repository's own front end makes and its server does not serve. |

And one about blast radius:

| Not covered | Why | What answers it |
|---|---|---|
| **The reach of a component the container invokes rather than the code — a security filter chain, an around-advice aspect, a `@ControllerAdvice`, a bean resolved through the interface it implements.** | Blast radius here is projected over the call graph: who calls the changed symbol, and which routes reach those callers. Nothing in the repository calls a container-wired component, so its measured call-graph fan-in is ~0 and every figure derived from it — affected endpoints, direct callers, rollback surface — reads as no impact. The fan-in figure is correct; using it as a risk proxy on this population is not. Publishing that as a low verdict would be a confident zero, which is the one thing this product does not do. | Such a change is flagged in `analysis_warnings` and its verdict is floored, never rated on fan-in. The reach itself is measured elsewhere and was there all along: `ask endpoints` resolves a gate annotation to the routes carrying it, `ask explain <class>` prints the request chain a configuration declares with its source line, and `ask posture --profile <set>` states what each profile leaves open. Projecting those into the blast radius (pointcut → routes, matcher → routes) is a measurement this command does not yet make. |

The one row above with a remedy in this build: `ask endpoints /path/to/repo --servlets`
lists the servlet-mounted HTTP surface as a population of its own — `web.xml` mappings and
`ServletRegistrationBean` registrations, with the file that declares each — and never merges
it into `endpoints.total`. Measured: openmrs-core 7 patterns, alfresco-community-repo 11,
including `/api/*` served by a WebScript servlet.

**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
must change, what each change reaches, and what a gate should block — and it removes none of
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
input.

**Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
as `licensing_review_needed`. This is inventory evidence, not legal advice.

**Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
`audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
indexes claims already in the payload; it does not add analysis or certify compliance.


---

## Pricing

> **🎉 Early-adoption: Pro is currently unlocked for everyone.** Every install runs with
> full Pro entitlements — no size gate, no key. The tiers below describe the model the
> paywall will return to later.
>
> **What that means concretely.** Ask the product: `ask auth status` answers in one block —
> `entitlement` (what runs today), `source` (*why* — a licence, the unlock, or the free tier),
> `authenticated` (whether a credential exists, which is a separate fact) and
> `when_it_changes` (what you lose when that source stops applying). A fresh install reads
> `entitlement: pro`, `source: early_adoption_unlock`, `authenticated: false` — unauthenticated
> *and* entitled, stated as two facts instead of one contradiction. When the unlock ends,
> gating returns **by repo size and automation, never by command**: `posture`, `endpoints`,
> `spring-audit` and `migrate-check` stay in the base tier at full output. Nothing you can run
> today becomes a paid-only command tomorrow.

**Gating is by repo size and automation — never by command.** Every command runs at full
power on Free for small and mid-size repos; you upgrade when the work gets bigger or automated.

| | **Free** — €0 | **Pro** — €19/mo · €190/yr per dev |
|---|---|---|
| Repo size | ≤ 500 Java source files | **> 500 Java files** (enterprise monoliths) |
| Commands | All of them, full output | Same commands, unlocked at scale |
| `impact` / `fix-bug` / `review-pr` / `modernize` | ✅ full on small repos | ✅ full on large repos (Free gets a capped preview) |
| `prepare-context delta` | 30 free runs/repo | unlimited — CI/CD automation |
| MCP local server, offline, no data egress | ✅ | ✅ |

**Non-Java repos are free at any size** — the size limit counts Java source files only.
ASK Engine monetises enterprise Java monoliths. Activate with `ask activate <key>`.
Full breakdown: [docs/PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md).

---

## Configuration & privacy

```bash
ask config              # version, config file path, telemetry status
ask config /repo        # + the repository's own sourcecode.config.json:
                        #   data labels, custom security annotations,
                        #   and any declaration that could not be used
ask telemetry enable    # anonymous telemetry is OFF by default (opt-in)
```

**Nothing is collected or transmitted unless you turn telemetry on** — not on the first run,
not in CI. If you do opt in, it collects version, OS, commands, flags, duration, repo-size
range, and errors: **no source code, paths, secrets, or output**. Turn it off again with
`ask telemetry disable`, `export SOURCECODE_TELEMETRY=0`, or `DO_NOT_TRACK=1`.

> **Auditing someone else's code — regulated, client-owned or public-sector?** Nothing to do.
> Telemetry was opt-out until 3.3.0; it is opt-in now (`docs/DEFECT-LEDGER.md` P-1), because a
> default you must remember to disable is the wrong default for third-party code. An explicit
> choice you made before is unchanged.

**Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain` about
project-specific authorization annotations via an optional `sourcecode.config.json` at the
repo root (otherwise they report `policy: "none_detected"`):

```json
{
  "customSecurityAnnotations": [
    { "fullyQualifiedName": "com.example.security.CustomSecurityAnnotation", "shortName": "CustomSecurityAnnotation" }
  ]
}
```

Matching endpoints report `policy: "custom"` and drop out of the `no_security_signal` count.

---

## Documentation

| Doc | What it covers |
|-----|----------------|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
| [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 |
| [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
| [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 |
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
| [PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md) | Free vs Pro, pricing model |
| [DEMO-5MIN.md](docs/DEMO-5MIN.md) | A reproducible 5-minute demo |
| [MANUAL-USUARIO.md](docs/MANUAL-USUARIO.md) | Guía de usuario en español |
| [PRODUCT_IDENTITY.md](docs/PRODUCT_IDENTITY.md) | `ask` (command) vs `sourcecode` (package/alias) |
| [privacy.md](docs/privacy.md) | Telemetry and data-handling policy |
| [DEFECT-LEDGER.md](docs/DEFECT-LEDGER.md) | Every defect found in the field, its class, and which release closed it — published on purpose |
| [spec/envelope-v1.md](docs/spec/envelope-v1.md) | The output format as an **open specification** — provenance, a named unit, a stated basis, declared non-coverage. Implementable by tools that are not this one; the field table is generated from the schema `ask schema envelope-v1` prints |
