Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,35 @@ only when an incompatible change is made to that surface. See

## [Unreleased]

## [1.4.0] — 2026-06-30

Feature release on top of `1.3.1`. (Cargo SemVer `1.4.0`; Python wheels `1.4.0`.)
Highlights: a new `loomweave-llm` provider crate (so `loomweave-core` links no
outbound HTTP client), the Warpline churn consumer lighting up the churn/recency
read surfaces, Rust-plugin dead-code reachability roots (ADR-054), and a batch of
federation-keying and graph-integrity fixes.

### Added

- **Warpline churn consumer.** Loomweave now consumes Warpline's frozen churn
read to populate the `high_churn` and `recently_changed` surfaces
(`entity_high_churn_list` / `entity_recent_change_list`). The consumer speaks
`warpline-mcp`'s newline JSON-RPC with a bounded timeout and honest
paging/keying disclosure. Federation is enrich-only and fail-soft — with
Warpline absent the surfaces degrade cleanly.
- **Rust-plugin dead-code reachability roots (ADR-054).** The Rust language
plugin now emits reachability-root tags — visibility / entry-point / test /
handler roots, framework handlers, public-method rooting, and edition-2024
`#[unsafe(no_mangle)]` / `#[unsafe(export_name)]` FFI entry-points — the Rust
analog of the Python public-surface roots, so Rust dead-code analysis no longer
reports the whole public API as dead.

### Changed

- **LLM / embedding providers extracted into a new `loomweave-llm` crate.** The
provider traits and implementations moved out of `loomweave-core`; a CI gate
now asserts `loomweave-core` links no outbound HTTP client. No change to the
`summary` API or provider configuration.
- **SEI git-rename consumer re-pointed to `legis`'s `/git/rename-feed`.**
`LegisGitRenameSource` now reads the committed leg of `legis`'s additive
superset endpoint `GET /git/rename-feed?base=…&head=HEAD` instead of the legacy
Expand All @@ -24,6 +51,45 @@ only when an incompatible change is made to that surface. See
working-tree authority). Enrich-only and fail-soft as before; the wire-drift
guard now warns on a legacy flat-array body or a `committed`-less envelope.
(Federation ledger B3.)
- **Filigree federation transport over newline JSON-RPC.** The filigree-mcp
federation client now speaks newline-delimited JSON-RPC instead of
`Content-Length` framing (#78).

### Fixed

- **Briefing-blocked entities keep their SEI on the read surface.** Federation
keying no longer nulls the Stable Entity Identity of briefing-blocked entities
on the MCP read path, so Filigree/Wardline lookups keyed by SEI resolve
(#79; PDR-0008).
- **Same-locator collisions are disclosed on the entity read path.** A duplicate
entity locator now surfaces as an entity-anchored `LMWV-DUPLICATE-LOCATOR`
finding anchored to the colliding (survivor) entity, so the shadowed
declaration is queryable from the entity read path instead of silently
resolving to a clean row (clarion-48af930f2a, #74).
- **Stale `contains` edge pruned when a file-scope claim moves.** The writer
prunes a stale parent/`contains` edge when a `file_scope` entity's claim moves,
self-healing the module/package dual-claim mismatch on re-emit
(clarion-abda98c869, #75).
- **Incremental re-analyze on a tag-schema move.** A plugin's files are
re-dispatched when its ontology tag schema changes between runs, so tag-driven
surfaces don't go stale on an incremental walk (clarion-e12d424f1d, #71).
- **Plugin findings can no longer forge the trusted anchor.**
`validate_plugin_finding` strips the host-reserved `anchor_entity_id` metadata
key, so a plugin-reported finding can no longer override the trusted file
anchor — which previously could hard-fail the analyze run on the findings
foreign key, or silently mis-associate the finding (#80).

### Tests

- Cross-repo conformance oracles for the loomweave↔filigree and
loomweave↔wardline seams (Filigree entity-associations, the Wardline taint-fact
wire, and the Wardline trust-vocabulary descriptor), pinning the wire bytes
each sibling produces or consumes so a silent drift reds in CI.

### Security

- Bumped `anyhow` `1.0.102` → `1.0.103` to clear a RUSTSEC soundness advisory in
`anyhow`'s `downcast_mut` (dtolnay/anyhow#451). Lockfile only; no API change.

## [1.3.1] — 2026-06-22

Expand Down
24 changes: 12 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ exclude = [
]

[workspace.package]
version = "1.3.1"
version = "1.4.0"
edition = "2024"
license = "MIT"
repository = "https://github.com/foundryside-dev/loomweave"
Expand Down
14 changes: 7 additions & 7 deletions crates/loomweave-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ anyhow.workspace = true
axum.workspace = true
blake3.workspace = true
clap.workspace = true
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-llm = { path = "../loomweave-llm", version = "1.3.1" }
loomweave-analysis = { path = "../loomweave-analysis", version = "1.3.1" }
loomweave-federation = { path = "../loomweave-federation", version = "1.3.1" }
loomweave-mcp = { path = "../loomweave-mcp", version = "1.3.1" }
loomweave-scanner = { path = "../loomweave-scanner", version = "1.3.1" }
loomweave-storage = { path = "../loomweave-storage", version = "1.3.1" }
loomweave-core = { path = "../loomweave-core", version = "1.4.0" }
loomweave-llm = { path = "../loomweave-llm", version = "1.4.0" }
loomweave-analysis = { path = "../loomweave-analysis", version = "1.4.0" }
loomweave-federation = { path = "../loomweave-federation", version = "1.4.0" }
loomweave-mcp = { path = "../loomweave-mcp", version = "1.4.0" }
loomweave-scanner = { path = "../loomweave-scanner", version = "1.4.0" }
loomweave-storage = { path = "../loomweave-storage", version = "1.4.0" }
dotenvy.workspace = true
fs2.workspace = true
hmac.workspace = true
Expand Down
6 changes: 3 additions & 3 deletions crates/loomweave-cli/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "maturin"

[project]
name = "loomweave"
version = "1.3.1"
version = "1.4.0"
description = "Loomweave — graph-aware code archaeology (Rust core)"
readme = "../../README.md"
requires-python = ">=3.11"
Expand All @@ -22,8 +22,8 @@ classifiers = [
# instead, move loomweave-plugin-rust to an [project.optional-dependencies]
# `rust` extra (installed via `loomweave[rust]`).
dependencies = [
"loomweave-plugin-python==1.3.1",
"loomweave-plugin-rust==1.3.1",
"loomweave-plugin-python==1.4.0",
"loomweave-plugin-rust==1.4.0",
]

[project.urls]
Expand Down
2 changes: 1 addition & 1 deletion crates/loomweave-federation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ workspace = true

[dependencies]
blake3.workspace = true
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-core = { path = "../loomweave-core", version = "1.4.0" }
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
Expand Down
8 changes: 4 additions & 4 deletions crates/loomweave-mcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ workspace = true
[dependencies]
async-trait.workspace = true
blake3.workspace = true
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-llm = { path = "../loomweave-llm", version = "1.3.1" }
loomweave-federation = { path = "../loomweave-federation", version = "1.3.1" }
loomweave-storage = { path = "../loomweave-storage", version = "1.3.1" }
loomweave-core = { path = "../loomweave-core", version = "1.4.0" }
loomweave-llm = { path = "../loomweave-llm", version = "1.4.0" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Publish loomweave-llm before dependent crates

When this 1.4.0 tag runs publish-crates, .github/workflows/release.yml publishes core/scanner/analysis/storage/federation/plugin-rust/mcp/cli but never publishes loomweave-llm, while this bumped dependency is converted into the registry dependency required by the published loomweave-mcp and loomweave-cli crates. I checked cargo publish --help: -p, --package selects the package(s) to publish, so dependencies are not uploaded implicitly; add publish loomweave-llm before the crates that depend on it or the crates.io release stalls when loomweave-mcp/loomweave-cli need loomweave-llm = 1.4.0.

Useful? React with 👍 / 👎.

loomweave-federation = { path = "../loomweave-federation", version = "1.4.0" }
loomweave-storage = { path = "../loomweave-storage", version = "1.4.0" }
reqwest.workspace = true
rusqlite.workspace = true
serde.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/loomweave-plugin-fixture/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ name = "loomweave-fixture-plugin"
path = "src/main.rs"

[dependencies]
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-core = { path = "../loomweave-core", version = "1.4.0" }
serde_json.workspace = true

[target.'cfg(unix)'.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion crates/loomweave-plugin-rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ name = "loomweave-rust-plugin"
path = "src/main.rs"

[dependencies]
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-core = { path = "../loomweave-core", version = "1.4.0" }
ignore = { workspace = true }
serde_json.workspace = true
syn = { version = "2", features = ["full", "extra-traits", "visit"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/loomweave-plugin-rust/plugin.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[plugin]
name = "loomweave-plugin-rust"
plugin_id = "rust"
version = "1.3.1"
version = "1.4.0"
protocol_version = "1.0"
# Bare basename per ADR-021 — the host refuses any path component. This is the
# DISCOVERY name; the cargo artifact is `loomweave-rust-plugin` (off-glob).
Expand Down
2 changes: 1 addition & 1 deletion crates/loomweave-storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ workspace = true

[dependencies]
blake3.workspace = true
loomweave-core = { path = "../loomweave-core", version = "1.3.1" }
loomweave-core = { path = "../loomweave-core", version = "1.4.0" }
deadpool-sqlite.workspace = true
rusqlite.workspace = true
serde.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions packaging/rust-plugin-dist/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

[package]
name = "loomweave-plugin-rust-dist"
version = "1.3.1"
version = "1.4.0"
edition = "2024"
license = "MIT"
repository = "https://github.com/foundryside-dev/loomweave"
Expand All @@ -31,4 +31,4 @@ name = "loomweave-plugin-rust"
path = "src/main.rs"

[dependencies]
loomweave-plugin-rust = { path = "../../crates/loomweave-plugin-rust", version = "1.3.1" }
loomweave-plugin-rust = { path = "../../crates/loomweave-plugin-rust", version = "1.4.0" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Regenerate the standalone Rust plugin lockfile

This release bump updates the standalone Rust plugin dist crate to depend on loomweave-plugin-rust 1.4.0, but the checked-in packaging/rust-plugin-dist/Cargo.lock still records the dist/core/plugin packages at older versions, so locked builds of this manifest fail before compiling because Cargo must rewrite the lockfile. I verified this against the reviewed tree with cargo metadata --locked --manifest-path packaging/rust-plugin-dist/Cargo.toml, and cargo metadata --help defines --locked as asserting that Cargo.lock remains unchanged; regenerate and commit this dist lockfile with the 1.4.0 bump.

Useful? React with 👍 / 👎.

2 changes: 1 addition & 1 deletion packaging/rust-plugin-dist/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "maturin"

[project]
name = "loomweave-plugin-rust"
version = "1.3.1"
version = "1.4.0"
description = "Loomweave Rust language plugin — JSON-RPC entity/edge extractor"
readme = "README.md"
requires-python = ">=3.11"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[plugin]
name = "loomweave-plugin-rust"
plugin_id = "rust"
version = "1.3.1"
version = "1.4.0"
protocol_version = "1.0"
# Bare basename per ADR-021 — the host refuses any path component. This is the
# DISCOVERY name; the cargo artifact is `loomweave-rust-plugin` (off-glob).
Expand Down
2 changes: 1 addition & 1 deletion plugins/python/plugin.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[plugin]
name = "loomweave-plugin-python"
plugin_id = "python"
version = "1.3.1"
version = "1.4.0"
protocol_version = "1.0"
# Bare basename per ADR-021 §Layer 1 + WP2 scrub commit eb0a41d — the host
# refuses manifests whose `executable` carries any path component.
Expand Down
2 changes: 1 addition & 1 deletion plugins/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "loomweave-plugin-python"
version = "1.3.1"
version = "1.4.0"
description = "Loomweave Python language plugin — v1.0 release"
readme = "README.md"
requires-python = ">=3.11"
Expand Down
2 changes: 1 addition & 1 deletion plugins/python/src/loomweave_plugin_python/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""loomweave-plugin-python — Python language plugin for Loomweave."""

__version__ = "1.3.1"
__version__ = "1.4.0"
4 changes: 2 additions & 2 deletions plugins/python/tests/test_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def _read_toml(path: Path) -> dict[str, Any]:


def test_package_version_matches_pyproject() -> None:
assert loomweave_plugin_python.__version__ == "1.3.1"
assert loomweave_plugin_python.__version__ == "1.4.0"


def test_plugin_version_lockstep_across_pyproject_manifest_and_module() -> None:
Expand All @@ -42,7 +42,7 @@ def test_plugin_version_lockstep_across_pyproject_manifest_and_module() -> None:
def test_manifest_declares_current_v1_ontology_only() -> None:
manifest = _read_toml(_PLUGIN_ROOT / "plugin.toml")

assert manifest["plugin"]["version"] == "1.3.1"
assert manifest["plugin"]["version"] == "1.4.0"
assert manifest["capabilities"]["runtime"]["wardline_aware"] is True
assert manifest["integrations"]["wardline"]["expected_descriptor_version"] == (
EXPECTED_DESCRIPTOR_VERSION
Expand Down
2 changes: 1 addition & 1 deletion plugins/python/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def test_initialize_roundtrip() -> None:
assert response["id"] == 1
result = response["result"]
assert result["name"] == "loomweave-plugin-python"
assert result["version"] == "1.3.1"
assert result["version"] == "1.4.0"
assert result["ontology_version"] == "0.9.0"
assert set(result["capabilities"]) == {"wardline"}
assert result["capabilities"]["wardline"]["status"] in {
Expand Down
2 changes: 1 addition & 1 deletion plugins/python/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.