Current section

Files

Jump to
rbt_weave CHANGELOG.md
Raw

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.55] - 2026-04-29
### Fixed
- Strip `custom:` prefix from amount badge display text and CSS classes in HTML output
## [0.2.54] - 2026-04-29
### Changed
- Fall back to GET on HEAD 4xx errors in URL verifier (many servers reject HEAD but accept GET)
## [0.2.53] - 2026-04-29
### Changed
- Increase MAX_FRAGMENT_BYTES from 768KB to 2MB for larger HTML case fragments
## [0.2.52] - 2026-04-28
### Changed
- Unify DSL type field: `org_type`, `event_type`, `doc_type`, `asset_type` replaced by `type` across all entity labels
- `field_constraint()` now takes a `Label` parameter for label-aware validation
- No backward compatibility: old prefixed field names are rejected
## [0.2.51] - 2026-04-28
### Added
- Add shared `countries` module with ISO 3166-1 alpha-2 validation (`is_valid_country_code`) and display name lookup (`country_name`)
### Changed
- Nationality field now validates as ISO 3166-1 alpha-2 country codes (hard error on non-ISO values like "French", "Indonesian")
- HTML `countries` module delegates to shared `crate::countries` for code-to-name mapping
## [0.2.50] - 2026-04-28
### Added
- Add `source_label` and `target_label` fields to `RelOutput` for index-optimized Neo4j relationship queries
## [0.2.49] - 2026-04-28
### Added
- Add `build_case_index_with_contents` — parallel case index build that retains file contents to avoid double reads
- Add `build_case_output_tracked_from_content` — accepts pre-read content to skip redundant file I/O
### Changed
- Parallelize `build_case_index` with rayon for faster case file scanning
### Fixed
- Fix `json_roundtrip` test for multi-nationality serialization format
## [0.2.48] - 2026-04-27
### Added
- Add `no_writeback` parameter to `build_case_output_tracked` — when true, errors if IDs are missing instead of writing them back to source files
## [0.2.47] - 2026-04-27
### Changed
- Change nationality from `Option<String>` to `Vec<String>` for multi-nationality support
- DSL now supports comma-separated nationality values (e.g. `nationality: CA, SY`)
## [0.2.46] - 2026-04-27
### Changed
- Reclassify verify error statuses: HTTP 400/406 now Suspicious (bot detection), 5xx now Warn (transient), connection errors now Warn; only 404 and other client errors fail exit code
## [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