julie-extract v2.8.0
v2.8.0
This minor release finishes the backend HTTP boundary lane: server-side
route/mount fact families for six more mainstream backend stacks (NestJS,
Kotlin + Spring, Laravel, Phoenix, axum, actix), the http.client_request.v1
extension to four more languages (Kotlin, PHP, Elixir, Rust), and per-framework
prefix-registration ("mount") families — all joined on the same
normalized_route_template (:param flavor) key introduced in v2.7.0, so
Miller can bridge outbound client calls to handler definitions across these
stacks too.
The static-vs-dynamic silence decision for the four new languages is made by a
single shared AST whole-argument allowlist helper (static_arg.rs, ADR-0005),
not by extending the byte-level source mask — see Contract Changes.
New Structural-Fact Families
Handler-definition facts (all emit route_template plus the cross-family
normalized_route_template join key in :param flavor, with attested
verb/verb_source and prefix/effective keys where the framework has them):
- TypeScript/JavaScript (NestJS):
nestjs.route.v1—@Get/@Post/… (and
@All, verb omitted) method decorators, joined to the@Controllerclass
prefix. - Kotlin (Spring): reuses the existing
spring.request_mapping.v1id
(languagesextended to[java, kotlin]) —@GetMapping/@RequestMapping
with class-prefix join, bracket multi-path arrays, andmethod=[...]
multi-verb expansion. - PHP (Laravel):
laravel.route.v1,laravel.resource_route.v1,
laravel.route_prefix.v1—Route::get/match/any,Route::resource,
andRoute::prefix(...)->group(...)/Route::group(['prefix'=>...])prefix
joins. - Elixir (Phoenix):
phoenix.route.v1,phoenix.resource_route.v1,
phoenix.forward.v1— router macros with nestedscopeprefixes,
resources, andforward. - Rust (axum):
axum.route.v1,axum.nest.v1—Router::new().route(...)
with per-verb method-router expansion and.nest(...)mounts;
single-assignment receiver tracing (poison on non-literal). - Rust (actix):
actix.attribute_route.v1,actix.scope_route.v1,
actix.mount.v1—#[get(...)]/#[route(...)]attribute macros (verb
always),web::scope(...).route(...)same-file scope joins, and
web::scope(...).configure/.servicemounts. Mirrors the shipped ASP.NET
attribute-vs-call routing split.
Outbound-call facts: http.client_request.v1 now also covers Kotlin (Ktor
client receiver.verb(url)), PHP (Guzzle and the Laravel Http facade),
Elixir (Req), and Rust (reqwest reqwest::get / client.get), in addition to
the v2.7.0 coverage.
Cross-Family Doctrine (unchanged from v2.7.0)
normalized_route_templateremains the universal join key::paramflavor,
computed per family from the raw source template.- M2 static-literal silence: only static string literals emit route or client
facts. Interpolations, concatenations,format!/sprintf/macro forms,
heredocs/sigils with interpolation, and identifier/const arguments stay
silent; a non-literal prefix poisons the prefix chain rather than guessing. - Verbs are recorded only when source-attested; verbless registrations
(@All, actixweb::route(), axumany, method-less@RequestMapping)
omitverb. - Prefix-registration ("mount") facts emit at the prefix's own definition site
withmount_path/normalized_mount_path(andmount_targetwhere a
same-file target exists); same-file-resolvable prefixes also flow into
route_group_prefix/effective_route_templateon the route fact itself.
Static-Literal Detection (ADR-0005)
The four new languages make the static-vs-dynamic decision via
static_route_arg(node, content, lang) — an AST allowlist run on the whole
route/URL argument expression, returning the literal's text only for an
approved static string-literal node and None for every wrapper. The vendored
tree-sitter grammars differ from a naive "interpolation-child" reading, so each
arm carries a grammar-verified guard: Kotlin also rejects an unescaped $ in
string_content; Elixir also rejects #{ in quoted_content (the ~S
capital-sigil case) and requires sigil_name ∈ {s, S}; PHP runs its allowlist
on the heredoc_body/nowdoc_body child. The byte-level SourceMask in
scan.rs is deliberately not extended to these languages.
Contract Changes
- Rust package versions change from
2.7.0to2.8.0. EXTRACTION_CONTRACT_VERSIONgains the trailingbackend-http-boundary-v2
marker (new pattern ids and newhttp.client_request.v1languages change the
canonical extraction shape).docs/contracts/structural-fact-patterns.jsonadds the new NestJS/Laravel/
Phoenix/axum/actix route and mount specs and the Kotlin extension of
spring.request_mapping.v1; thehttp.client_request.v1spec gains
kotlin/php/elixir/rust.- SQLite schema version remains
3. Artifact integer
extract_contract_versionremains3. JSONL schema version remains3.
JSON report schema version remains3. - Parser dependency versions are unchanged.
Documented Exclusions
Per-language deferrals are recorded as open_gaps (reason + closure task) on
the capability rows, not silent gaps: Ktor server routing and
RouterFunction/coRouter (Kotlin); Symfony #[Route] attributes and
cross-file RouteServiceProvider prefixes (PHP); LiveView/socket/channel and
cross-file scope/forward prefixes (Elixir); actix cross-file
configure/service scopes, web::resource guard forms, axum 0.7 :id
recording, cross-file .nest joins, and deferred clients
(OkHttp/Retrofit/WebClient, Symfony HttpClient/curl, Tesla/HTTPoison/Finch,
hyper/ureq). nestjs.global_prefix is out by design (no safe Miller consumer).
Miller Consumer Follow-Up (cross-repo)
docs/plans/2026-07-03-miller-http-boundary-consumer-followup.md tracks the
Miller-side work. Verified against the current consumer: Kotlin Spring routes
(reused spring.request_mapping.v1) and all four new client languages (reused,
non-language-gated http.client_request.v1) join today with zero Miller
changes. The eight new server-route ids and four new mount families need
whitelist + route-family wiring on Miller's side to join; they are correct and
evidence-bearing regardless, and same-file prefixes degrade gracefully via
effective_route_template.
Verification
Local and release gates passed for commit
2dbdcad327f8025fe0f6c3aedba6ece73e8323a1:
cargo test --workspace --quietcargo clippy --workspace --all-targets --all-features --no-deps -- -D warningscargo fmt --all -- --checkgit diff --check HEADcargo test -p julie-extractors --features test-golden structural_fact_registrycargo test -p julie-extractors --features test-golden golden_fixtures_match_canonical_extractioncargo test -p julie-extractors --features test-capability-matrix capability_matrixnode scripts/language-data-quality-report.mjs --strict(silent_cells 0, quality_bar_debts 0)scripts/check-agent-doc-sync.sh(AGENTS.md/CLAUDE.md synced)cargo xtask release preflight --version 2.8.0(4 targets, 19 inputs)- GitHub CI run
28707779894:Fast Gates, passed - Release workflow run
28707784242: all four binary builds and the GitHub Release job passed - Downloaded published Apple Silicon binary dogfood passed:
julie-extract 2.8.0
Published Assets
| Target | Asset | Size | GitHub asset digest |
|---|---|---|---|
| Linux x86_64 | julie-extract-v2.8.0-x86_64-unknown-linux-gnu.tar.gz |
10,758,539 bytes | sha256:185bd0cdd2b0ea45ab588fbf01fbc0d83953453c4423115cf4febcadf034ac8f |
| macOS Apple Silicon | julie-extract-v2.8.0-aarch64-apple-darwin.tar.gz |
10,523,676 bytes | sha256:75424faf62b98afd02f5268919dd5269db6146b1e410ea250a20a10e9afae8af |
| macOS Intel | julie-extract-v2.8.0-x86_64-apple-darwin.tar.gz |
10,458,063 bytes | sha256:12c3e6271cb73226bad1dcee6a8e508c04a3e2d7b312866352cb6b19b9b1c6d2 |
| Windows x86_64 | julie-extract-v2.8.0-x86_64-pc-windows-msvc.zip |
9,759,538 bytes | sha256:fb2d2df16ddb92eea4d47bee384bdf225a63b7a054087cf56f462a73a3128e0b |
Release metadata verified that v2.8.0 is not a draft and not a prerelease.
Downloaded assets matched the GitHub asset digests, and each archive stores the
binary under dist/<target>/julie-extract or dist/<target>/julie-extract.exe
with the checksum file beside it.