Packages
rbt_weave
0.2.45
0.2.67
0.2.66
0.2.65
0.2.64
0.2.63
0.2.62
0.2.61
0.2.60
0.2.59
0.2.58
0.2.57
0.2.56
0.2.55
0.2.54
0.2.53
0.2.52
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.46
0.2.45
0.2.44
0.2.43
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.34
0.2.33
0.2.32
0.2.31
0.2.30
0.2.29
0.2.28
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Graph conflict detection and image processing NIFs for OSINT knowledge graphs, powered by Rust.
Current section
Files
Jump to
Current section
Files
CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.2.45] - 2026-04-26
### Changed
- Increase max HTML fragment size from 512KB to 768KB
## [0.2.44] - 2026-04-26
### Changed
- Verify cache: tiered TTL (ok=90d, rate_limited=7d, warn=1d; error/suspicious always recheck)
- Verify cache: `RwLock` for thread-safe concurrent read/write
- Verify cache: atomic save (write to tmp file, then rename)
- Verify cache: log entry counts on load/save with prune stats
- Refactored `validate_front_matter` into focused helper functions
## [0.2.43] - 2026-04-26
### Added
- `Convicted` variant for `PersonStatus` enum
- `Defunct` variant for `OrgStatus` enum
## [0.2.42] - 2026-04-25
### Changed
- Verify status classification: 429 is now `RateLimited` (URL is fine, just hit rate limit), 401/403 is `Suspicious` (possible bot detection)
- 429 responses no longer retried (accepted as-is)
- Suspicious (401/403) results not cached (always re-checked)
- User-Agent changed to generic browser string to reduce bot detection
- Categorized URL lists (rate_limited, suspicious, errors, warn) printed to stdout after verify
### Added
- `CheckStatus::RateLimited` and `CheckStatus::Suspicious` variants
- `print_url_list` helper for categorized stdout output
## [0.2.41] - 2026-04-25
### Changed
- Verify redesigned for world scale: global URL dedup across all cases, single multi-threaded runtime, per-domain rate limiting (default 4 concurrent per domain), retries with exponential backoff for 429/503/timeout (default 2 retries), HEAD-rejection domain learning
- Default concurrency raised from 16 to 64
- MAX_URLS_PER_RUN raised from 10,000 to 500,000
- MAX_CACHE_ENTRIES raised from 50,000 to 500,000
### Added
- `--domain-concurrency` CLI flag (default 4)
- `--retries` CLI flag (default 2)
- `UrlEntry::new()` public constructor
- `dashmap` and `url` dependencies
## [0.2.40] - 2026-04-25
### Added
- Countries index page (`/countries.html`) listing all countries with case counts
- Tags index page (`/tags.html`) listing all tags with case counts
- Sitemap now includes `/countries` and `/tags` index URLs and individual tag URLs
## [0.2.39] - 2026-04-25
### Added
- Deduplicate `urls` per node and `source_urls` per relationship at output time
- Validator rejects duplicate URLs in entity url lists, front matter sources, and relationship source urls
## [0.2.38] - 2026-04-24
### Fixed
- Move `countries.json` into `crates/weave-content/` so it is included in the crates.io tarball (previously `include_str!` traversed outside the package boundary)
- Add `set -o pipefail` to all publish steps in release workflow to prevent masking `cargo publish` failures through `tee`
- Add explicit `include` list to `weave-content` `Cargo.toml` to ensure `countries.json` is packaged
## [0.2.37] - 2026-04-24
### Changed
- Refactored 1918-line `html.rs` monolith into 11 focused modules under `html/` directory
- Country names now loaded from `countries.json` (249 ISO 3166-1 codes) via `include_str!` + `OnceLock`
- Added NIF `country_names/0` returning raw JSON for Elixir consumption
- Added `countries.json` to hex package files
### Fixed
- All clippy pedantic warnings: wildcard imports, uninlined format args, doc backticks, match_same_arms
- Stale tests expecting old limits (MAX_SOURCES=20, MAX_RELATED_CASES=10, MAX_URLS_PER_RUN=2001)
- Merged duplicate transliteration match arms for Icelandic eth/Croatian d-stroke
## [0.2.36] - 2026-04-24
### Added
- Country pages: `render_country_page()` generates HTML listing all cases for a country
- `generate_country_pages()` writes `countries/{cc}.html` files during HTML output
- Country codes included in sitemap
### Changed
- Country badges are now clickable `<a>` links pointing to `/countries/{cc}` instead of `<span>` elements
## [0.2.35] - 2026-04-24
### Fixed
- Sync country name mapping: add EC (Ecuador), PA (Panama), ZW (Zimbabwe); standardize AE display to "UAE"
## [0.2.34] - 2026-04-24
### Added
- Country badge display in static HTML: case headers, entity case lists, tag page listings, and OG titles now show the country derived from the case slug
- Support for `multinational` and `int` scope segments in case/entity slugs (per ADR-018)
- 15 missing country codes in the country name map (BA, CD, CL, ET, LY, NP, PE, PS, RS, RW, SD, SY, UA, VE, YE)
- ASCII transliteration of diacritics in filenames and URL slugs: NFD decomposition + combining mark removal + manual mapping for non-decomposable Latin characters (ł→l, đ→d, ı→i, ø→o, etc.)
### Changed
- NFC normalization in `path_to_slug` now also strips diacritics for ASCII-safe URLs
- `to_kebab_case` strips diacritics before slugifying (e.g. "Prlić" → "prlic")
## [0.2.33] - 2026-04-24
### Changed
- Increase limits for worldwide coverage: case tags (10→20), entity tags (5→10), sources (20→50), related cases (10→25), involved (50→100), entities per file (50→100), tag categories (10→20), tags per category (30→60), total tags (200→500), URLs per verify run (2k→10k), timeline edges (200→500), cache entries (10k→50k), relationships per file (200→500)
## [0.2.32] - 2026-04-22
### Added
- `--quiet` / `-q` flag for `validate` command: suppresses per-entity and per-relationship detail lines, showing only file-level summaries, errors/warnings, and a final summary line with totals
## [0.2.31] - 2026-04-22
### Added
- `commands` module in `weave-content` library: extracts `validate()`, `verify()`, and `check_staleness()` orchestration functions from `main.rs` into public library API, enabling `loom-seed` to reuse the same logic without duplication
### Changed
- `weave-content` CLI now delegates to `commands::*` library functions instead of inline orchestration
## [0.2.30] - 2026-04-22
### Added
- Promote custom enum values to first-class types: 4 roles (militant, criminal, religious_leader, rebel_leader), 1 org type (militant_group), 9 case types (terrorism, negligence, drug_trafficking, sexual_assault, human_trafficking, environmental_crime, human_rights_violation, organized_crime, drug_manufacturing), 20 event types (bombing, suicide_bombing, massacre, execution, death, release, report, discovery, disaster, deportation, shooting, kidnapping, prison_escape, petition, surrender, confession, hijacking, assassination, protest, sanctions)
- `date_of_death` field for person entities across parser, output, and HTML renderer
### Fixed
- Test compilation errors: missing `sources` argument in `build_output` test calls, missing `tagline` field in HTML test `NodeOutput` construction
## [0.2.29] - 2026-04-21
### Added
- `check-staleness` subcommand for ADR-021 phase 1: offline structural analysis of DSL case files detecting stale statuses, status-event mismatches, and missing verdict events (9 rules, configurable thresholds)
## [0.2.28] - 2026-04-21
### Added
- Redirect collision guard in `weave-content validate`: checks `redirects.yaml` before registry loading to prevent files at old redirected paths
## [0.2.27] - 2026-04-21
### Added
- `assault` case type variant in content DSL parser
## [0.2.26] - 2026-04-21
### Added
- `tagline` field in case front matter (max 280 chars) for sharing/display
- Tagline renders as `<blockquote class="loom-tagline">` in case HTML header
- Tagline overrides og:description when present
- `data-og-tagline` attribute on case HTML root element
### Changed
- Rename "canvas" to "wall": `/canvas/` routes become `/walls/`, CSS class
`loom-canvas-link` becomes `loom-wall-link`, link text "View on canvas"
becomes "View on the wall"
## [0.2.25] - 2026-04-20
### Fixed
- Writeback appends to existing `## Involved` section instead of creating duplicate
## [0.2.24] - 2026-04-20
### Changed
- Generate INVOLVED_IN relationships for inline entities (events), not just registry entities
## [0.2.23] - 2026-04-20
### Changed
- Move `#[allow(clippy::implicit_hasher)]` and `#[allow(clippy::struct_field_names)]` to crate level
- Remove stale `#[allow(clippy::too_many_lines)]` from `cmd_verify` (only 41 lines)
- Split `generate_html_output` (279 lines) into orchestrator + 6 focused helpers
- Split `validate_fields` (153 lines) into `validate_single_field` + `validate_list_field`
- Deduplicate URL verification pipeline into shared `run_url_verification`
- Split `cmd_build` (156 lines) into `load_build_cache` + `hash_content_files` + `build_cases` + `finalize_build_cache`
## [0.2.22] - 2026-04-20
### Changed
- Render inline markdown (bold, italic, links, code) in case summary instead of escaping
## [0.2.21] - 2026-04-20
### Changed
- Remove backward compat for ` - key: value` relationship field format
- Only accept ` key: value` format for relationship fields
- Refactor writeback.rs: extract `insert_front_matter_id`, `insert_body_id`, `strip_id_prefix`, `append_involved_section`
- Fix duplicate ID insertion bug for body elements (relationships, timeline edges, etc.)
## [0.2.20] - 2026-04-20
### Fixed
- Writeback replaces empty `id:` field instead of inserting duplicate
## [0.2.19] - 2026-04-20
### Fixed
- Include cases without `id:` in case index for related case resolution
## [0.2.18] - 2026-04-20
### Added
- Add `pardoned` status to `CaseStatus` enum
## [0.2.17] - 2026-04-20
### Changed
- Render aliases as inline comma-separated text instead of `<ul>/<li>`
- Render entity URLs as domain-only link text with `·` separators instead of `<ul>/<li>`
## [0.2.16] - 2026-04-20
### Fixed
- Fix multi-line comma-separated list field continuation (e.g. aliases spanning multiple lines)
### Added
- Render entity URLs as clickable links in HTML output (`<div class="loom-urls">`)
## [0.2.15] - 2026-04-19
### Added
- Deterministic ID writeback for `preceded_by`, `involved_in`, and `related_to` relationships
- `## Involved` section parsing and creation in case files
- `## Timeline` bullet format parser with `id:` field support (replaces chain format)
- `TimelineEdge` and `InvolvedIn` writeback kinds
- Writeback round-trip tests for all new relationship types
### Changed
- Timeline parser only accepts bullet format (`- A -> B`); chain format removed
- `InvolvedIn` writeback carries entity name for automatic section creation
## [0.2.14] - 2026-04-19
### Fixed
- Fix double-hashing of already-rewritten thumbnail URLs in HTML renderer
## [0.2.13] - 2026-04-19
### Added
- `generate_html_output()` public API in lib.rs for reuse by loom-seed
## [0.2.12] - 2026-04-19
### Added
- Structured `AmountEntry` type replacing string amount/currency pairs on relationships and case nodes
- `amounts:` DSL field with approximate markers, currency, and labeled entries (bribe, fine, embezzlement, etc.)
- `fraud` amount label
- `related_to` relationship type and `## Related Cases` content DSL section with graph edges
- `CaseIndex` pre-pass for cross-case title/NULID resolution
- `build_case_index()` public API in lib.rs for reuse by loom-seed
- Human-readable number formatting: million/billion/trillion for numbers >= 1M
- Improved HTML: individual amount badges, financial details as definition list, related cases as cards
- HTML rendering for asset, document, and event entity fields
- Country-scoped tag pages, jurisdiction/nationality country name display
- Consistent enum formatting across all HTML sections
### Changed
- Financial details section moved above sources for visibility
- `INVOLVED_IN` relationships now only generated for registry entities (people/organizations), not inline events
### Fixed
- Duplicate `INVOLVED_IN` edges from events to case nodes
## [0.2.11] - 2026-04-19
### Added
- Case as first-class graph node (ADR-019): `slug`, `case_type` fields on Case nodes
- `INVOLVED_IN` relationship type for entity-case connections
- NULID auto-generation and writeback for case files (`nulid:` frontmatter field)
- `index.json` generation mapping NULID to slug for static route resolution
- Slug-based static HTML output URLs
- `data-og-image` attribute in HTML output for OG image meta tags
- Cross-file duplicate relationship ID validation in `validate` command
- `CaseNulid` writeback variant for correct `nulid:` field (not `id:`)
### Fixed
- Case NULID writeback now uses `nulid:` field instead of creating duplicate `id:` field
## [0.2.10] - 2026-04-18
### Changed
- **Breaking:** Rename entity directories: `actors/` → `people/`, `institutions/` → `organizations/`
- **Breaking:** Rename DSL section headings: `## Actors` → `## People`, `## Institutions` → `## Organizations`
- **Breaking:** Rename conflict detection rel types: `DONATED_TO` → `PAID_TO`, `CONTRACTED_WITH` → `AWARDED_CONTRACT`, `LOBBIED_FOR` → `LOBBIED`
- **Breaking:** Rename conflict detection labels: `Actor` → `Person`, `Institution` → `Organization`, `PublicRecord` → `Event`
- Update COI pattern names: "Donation-Appointment Cycle" → "Payment-Appointment Cycle", "Contract Kickback Cycle" → "Contract-Payment Cycle", "Donor Influence Chain" → "Payment Influence Chain"
- Hub detection now matches `Person` → `Organization` pairs (was `Actor` → `Institution`)
- Rewrite DSL.md to reflect all ADR-014 changes (new labels, fields, rel types, enum values)
## [0.2.9] - 2026-04-18
### Added
- Detect duplicate event names across case files in `validate` command
- Verify registry entity (actors/institutions) thumbnail URLs in `verify` command
## [0.2.8] - 2026-04-17
### Fixed
- Fix duplicate ID writeback for shared registry entities when building multiple cases
(`writeback_registry_entities` now checks if the entity file already has an `id:` in front matter before writing)
## [0.2.7] - 2026-04-17
### Fixed
- Add User-Agent header to weave-image downloads to prevent Wikipedia 403 blocks
### Changed
- Switch from lossless to lossy WebP encoding via `libwebp-sys` (quality 80, retry at 60 if over limit)
- Increase max thumbnail output size from 50 KB to 100 KB
## [0.2.6] - 2026-04-17
### Changed
- Remove S3/thumbnail infrastructure from weave-content (moved to private loom-seed binary)
- Make `download_async` public in weave-image for direct async usage
- Upgrade reqwest 0.12 to 0.13 (feature `rustls-tls` renamed to `rustls`)
- Upgrade sha2 0.10 to 0.11
## [0.2.5] - 2026-04-17
### Added
- Library API for weave-content: `resolve_content_root`, `load_registry`, `resolve_case_files`, `build_case_output` public functions for embedding in other binaries
## [0.2.4] - 2026-04-17
### Fixed
- Remove weave-content from workspace members to fix hex package compilation
(cargo metadata failed because weave-content source files are not included in the hex package)
- Make weave-content a standalone crate with explicit config instead of workspace inheritance
## [0.2.3] - 2026-04-17
### Fixed
- Fix clippy pedantic errors: wildcard match for single variant, redundant closure, function too many lines
- Remove unused `entries()` method from `EntityRegistry`
- Extract `writeback_registry_entities` and `write_case_output` helpers from `build_single_case`
## [0.2.2] - 2026-04-17
### Added
- **weave-content** crate published to crates.io (`cargo install weave-content`)
- Content DSL parser, validator, and builder for case files
- Shared entity registry: standalone actor/institution files with cross-file name resolution
- NULID write-back: `build` generates IDs and writes them back to source files
- Auto-discover: finds `actors/`, `institutions/`, `cases/` directories from content root
- Commands: `validate`, `verify`, `build`
### Fixed
- NEXT relationship IDs no longer written back to timeline section during build
(timeline chains are `Event A -> Event B` syntax, not bullet-list relationships)
## [0.2.1] - 2026-04-16
### Added
- `thumbnail_key/1` and `process_thumbnail/1` NIF exports in the bridge crate
- `Weave.Image` Elixir module wrapping image processing NIFs
### Changed
- Removed external site references from READMEs
## [0.2.0] - 2026-04-16
### Added
- **weave-image** crate for thumbnail processing
- Download images from URLs with 5 MB size limit and 15s timeout
- Center-crop and resize to 256x256 lossless WebP thumbnails
- Deterministic storage keys via SHA-256 of source URL (`thumbnails/{hex[0..32]}.webp`)
- Output size capped at 50 KB
- `thumbnail_key/1`, `download/1`, `resize_to_webp/1`, `process_thumbnail/1`
- Unit tests for resize, key generation, size limits, error cases
- Per-crate README files for crates.io
## [0.1.0] - 2026-04-16
### Added
- **weave-graph** crate for conflict-of-interest pattern detection on knowledge graphs
- `Node` and `Edge` types for subgraph representation (NULID-based identifiers)
- `Subgraph` and `IndexedSubgraph` with O(1) adjacency list lookups
- Cycle detection -- enumerate directed simple cycles matching edge-type sequences
- Path detection -- constrained DFS matching edge types and node labels against templates
- Hub detection -- flag Actor-Institution pairs with concentrated influence edges
- Six built-in patterns: COI-001 through COI-006
- Configurable `DetectOpts` with max depth and pattern ID filtering
- Property-based tests via `proptest` for correctness guarantees
- Performance benchmarks: <50ms for 10K nodes / 50K edges
- **weave_nif** crate providing Rustler NIF bridge
- `health_check/0` -- verify NIF is loaded
- `detect_conflicts/2` -- JSON-in, JSON-out conflict detection on dirty CPU scheduler
- **rbt_weave** Elixir hex package
- `Weave.Native` -- low-level NIF bindings via Rustler
- `Weave.Graph` -- public API delegating to `Weave.Native`
- Publishable to both [crates.io](https://crates.io) (Rust) and [hex.pm](https://hex.pm) (Elixir)
[Unreleased]: https://github.com/redberrythread/weave/compare/v0.2.8...HEAD
[0.2.8]: https://github.com/redberrythread/weave/compare/v0.2.7...v0.2.8
[0.2.7]: https://github.com/redberrythread/weave/compare/v0.2.6...v0.2.7
[0.2.6]: https://github.com/redberrythread/weave/compare/v0.2.5...v0.2.6
[0.2.5]: https://github.com/redberrythread/weave/compare/v0.2.4...v0.2.5
[0.2.4]: https://github.com/redberrythread/weave/compare/v0.2.3...v0.2.4
[0.2.3]: https://github.com/redberrythread/weave/compare/v0.2.2...v0.2.3
[0.2.2]: https://github.com/redberrythread/weave/compare/v0.2.1...v0.2.2
[0.2.1]: https://github.com/redberrythread/weave/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/redberrythread/weave/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/redberrythread/weave/releases/tag/v0.1.0